仅检索 MongoDB 集合中对象数组中的查询元素

发布于 2024-09-28 02:42:44 字数 1287 浏览 8 评论 0原文

假设我的集合中有以下文档:

{  
   "_id":ObjectId("562e7c594c12942f08fe4192"),
   "shapes":[  
      {  
         "shape":"square",
         "color":"blue"
      },
      {  
         "shape":"circle",
         "color":"red"
      }
   ]
},
{  
   "_id":ObjectId("562e7c594c12942f08fe4193"),
   "shapes":[  
      {  
         "shape":"square",
         "color":"black"
      },
      {  
         "shape":"circle",
         "color":"green"
      }
   ]
}

执行查询:

db.test.find({"shapes.color": "red"}, {"shapes.color": 1})

db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})

返回匹配的文档(文档1),但始终包含形状中的所有数组项:

{ "shapes": 
  [
    {"shape": "square", "color": "blue"},
    {"shape": "circle", "color": "red"}
  ] 
}

但是,我会想要仅使用包含 color=red 的数组来获取文档(文档 1)

{ "shapes": 
  [
    {"shape": "circle", "color": "red"}
  ] 
}

我该怎么做?

Suppose you have the following documents in my collection:

{  
   "_id":ObjectId("562e7c594c12942f08fe4192"),
   "shapes":[  
      {  
         "shape":"square",
         "color":"blue"
      },
      {  
         "shape":"circle",
         "color":"red"
      }
   ]
},
{  
   "_id":ObjectId("562e7c594c12942f08fe4193"),
   "shapes":[  
      {  
         "shape":"square",
         "color":"black"
      },
      {  
         "shape":"circle",
         "color":"green"
      }
   ]
}

Do query:

db.test.find({"shapes.color": "red"}, {"shapes.color": 1})

Or

db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})

Returns matched document (Document 1), but always with ALL array items in shapes:

{ "shapes": 
  [
    {"shape": "square", "color": "blue"},
    {"shape": "circle", "color": "red"}
  ] 
}

However, I'd like to get the document (Document 1) only with the array that contains color=red:

{ "shapes": 
  [
    {"shape": "circle", "color": "red"}
  ] 
}

How can I do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(20

北座城市 2024-10-05 02:42:44

MongoDB 2.2 的新 $elemMatch 投影运算符提供了另一种方法来更改返回的文档以仅包含 第一个 匹配的 shapes 元素:

db.test.find(
    {"shapes.color": "red"}, 
    {_id: 0, shapes: {$elemMatch: {color: "red"}}});

返回:

{"shapes" : [{"shape": "circle", "color": "red"}]}

在 2.2 中,您还可以使用 < a href="http://docs.mongodb.org/manual/reference/operator/projection/positional/#proj._S_" rel="noreferrer">$ 投影运算符,其中投影对象字段名称中的 $ 表示查询中该字段的第一个匹配数组元素的索引。以下返回与上面相同的结果:

db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.

MongoDB 3.2 更新

从 3.2 版本开始,您可以使用新的 $filter 聚合运算符,用于在投影期间过滤数组,其优点是包含全部 匹配,而不仅仅是第一个。

db.test.aggregate([
    // Get just the docs that contain a shapes element where color is 'red'
    {$match: {'shapes.color': 'red'}},
    {$project: {
        shapes: {$filter: {
            input: '$shapes',
            as: 'shape',
            cond: {$eq: ['$shape.color', 'red']}
        }},
        _id: 0
    }}
])

结果:

[ 
    {
        "shapes" : [ 
            {
                "shape" : "circle",
                "color" : "red"
            }
        ]
    }
]
: 1});

MongoDB 3.2 更新

从 3.2 版本开始,您可以使用新的 $filter 聚合运算符,用于在投影期间过滤数组,其优点是包含全部 匹配,而不仅仅是第一个。

结果:

MongoDB 2.2's new $elemMatch projection operator provides another way to alter the returned document to contain only the first matched shapes element:

db.test.find(
    {"shapes.color": "red"}, 
    {_id: 0, shapes: {$elemMatch: {color: "red"}}});

Returns:

{"shapes" : [{"shape": "circle", "color": "red"}]}

In 2.2 you can also do this using the $ projection operator, where the $ in a projection object field name represents the index of the field's first matching array element from the query. The following returns the same results as above:

db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.

MongoDB 3.2 Update

Starting with the 3.2 release, you can use the new $filter aggregation operator to filter an array during projection, which has the benefit of including all matches, instead of just the first one.

db.test.aggregate([
    // Get just the docs that contain a shapes element where color is 'red'
    {$match: {'shapes.color': 'red'}},
    {$project: {
        shapes: {$filter: {
            input: '$shapes',
            as: 'shape',
            cond: {$eq: ['$shape.color', 'red']}
        }},
        _id: 0
    }}
])

Results:

[ 
    {
        "shapes" : [ 
            {
                "shape" : "circle",
                "color" : "red"
            }
        ]
    }
]
: 1});

MongoDB 3.2 Update

Starting with the 3.2 release, you can use the new $filter aggregation operator to filter an array during projection, which has the benefit of including all matches, instead of just the first one.

Results:

醉城メ夜风 2024-10-05 02:42:44

MongoDB 2.2+ 中新的聚合框架提供了 Map/Reduce 的替代方案。 $unwind 运算符可用于分隔您的 shapes 数组放入可匹配的文档流中:

db.test.aggregate(
  // Start with a $match pipeline which can take advantage of an index and limit documents processed
  { $match : {
     "shapes.color": "red"
  }},
  { $unwind : "$shapes" },
  { $match : {
     "shapes.color": "red"
  }}
)

结果:

{
    "result" : [
        {
            "_id" : ObjectId("504425059b7c9fa7ec92beec"),
            "shapes" : {
                "shape" : "circle",
                "color" : "red"
            }
        }
    ],
    "ok" : 1
}

The new Aggregation Framework in MongoDB 2.2+ provides an alternative to Map/Reduce. The $unwind operator can be used to separate your shapes array into a stream of documents that can be matched:

db.test.aggregate(
  // Start with a $match pipeline which can take advantage of an index and limit documents processed
  { $match : {
     "shapes.color": "red"
  }},
  { $unwind : "$shapes" },
  { $match : {
     "shapes.color": "red"
  }}
)

Results in:

{
    "result" : [
        {
            "_id" : ObjectId("504425059b7c9fa7ec92beec"),
            "shapes" : {
                "shape" : "circle",
                "color" : "red"
            }
        }
    ],
    "ok" : 1
}
俏︾媚 2024-10-05 02:42:44

另一种有趣的方法是使用 $redact,这是一个MongoDB 2.6 的新聚合功能。如果您使用 2.6,则不需要 $unwind,如果您有大型数组,这可能会导致性能问题。

db.test.aggregate([
    { $match: { 
         shapes: { $elemMatch: {color: "red"} } 
    }},
    { $redact : {
         $cond: {
             if: { $or : [{ $eq: ["$color","red"] }, { $not : "$color" }]},
             then: "$DESCEND",
             else: "$PRUNE"
         }
    }}]);

$redact “根据文档本身存储的信息限制文档的内容”。因此它只会在文档内部运行。它基本上会从上到下扫描您的文档,并检查它是否与您在 $cond 中的 if 条件匹配,如果匹配,它将保留内容( $$DESCEND) 或删除($$PRUNE)。

在上面的示例中,首先 $match 返回整个 shapes 数组,然后 $redact 将其精简为预期结果。

请注意,{$not:"$color"} 是必需的,因为它也会扫描顶部文档,并且如果 $redact 未找到 color顶层的 字段将返回 false ,这可能会删除我们不想要的整个文档。

Another interesing way is to use $redact, which is one of the new aggregation features of MongoDB 2.6. If you are using 2.6, you don't need an $unwind which might cause you performance problems if you have large arrays.

db.test.aggregate([
    { $match: { 
         shapes: { $elemMatch: {color: "red"} } 
    }},
    { $redact : {
         $cond: {
             if: { $or : [{ $eq: ["$color","red"] }, { $not : "$color" }]},
             then: "$DESCEND",
             else: "$PRUNE"
         }
    }}]);

$redact "restricts the contents of the documents based on information stored in the documents themselves". So it will run only inside of the document. It basically scans your document top to the bottom, and checks if it matches with your if condition which is in $cond, if there is match it will either keep the content($$DESCEND) or remove($$PRUNE).

In the example above, first $match returns the whole shapes array, and $redact strips it down to the expected result.

Note that {$not:"$color"} is necessary, because it will scan the top document as well, and if $redact does not find a color field on the top level this will return false that might strip the whole document which we don't want.

鼻尖触碰 2024-10-05 02:42:44

注意:这个答案提供了一个在 MongoDB 2.2 及更高版本的新功能推出之前当时相关的解决方案。如果您使用的是更新版本的 MongoDB,请参阅其他答案。

字段选择器参数仅限于完整属性。它不能用于选择数组的一部分,只能用于选择整个数组。我尝试使用 $ 位置运算符,但这并没有工作。

最简单的方法是在客户端中过滤形状

如果您确实需要直接从 MongoDB 获得正确的输出,您可以使用map-reduce来过滤形状。

function map() {
  filteredShapes = [];

  this.shapes.forEach(function (s) {
    if (s.color === "red") {
      filteredShapes.push(s);
    }
  });

  emit(this._id, { shapes: filteredShapes });
}

function reduce(key, values) {
  return values[0];
}

res = db.test.mapReduce(map, reduce, { query: { "shapes.color": "red" } })

db[res.result].find()

Caution: This answer provides a solution that was relevant at that time, before the new features of MongoDB 2.2 and up were introduced. See the other answers if you are using a more recent version of MongoDB.

The field selector parameter is limited to complete properties. It cannot be used to select part of an array, only the entire array. I tried using the $ positional operator, but that didn't work.

The easiest way is to just filter the shapes in the client.

If you really need the correct output directly from MongoDB, you can use a map-reduce to filter the shapes.

function map() {
  filteredShapes = [];

  this.shapes.forEach(function (s) {
    if (s.color === "red") {
      filteredShapes.push(s);
    }
  });

  emit(this._id, { shapes: filteredShapes });
}

function reduce(key, values) {
  return values[0];
}

res = db.test.mapReduce(map, reduce, { query: { "shapes.color": "red" } })

db[res.result].find()
昵称有卵用 2024-10-05 02:42:44

更好的是,您可以使用 $slice 查询匹配的数组元素,这有助于返回数组中的重要对象。

db.test.find({"shapes.color" : "blue"}, {"shapes.$" : 1})

当您知道元素的索引时, $slice 很有帮助,但有时您想要
无论哪个数组元素符合您的条件。可以返回匹配的元素
$ 运算符。

Better you can query in matching array element using $slice is it helpful to returning the significant object in an array.

db.test.find({"shapes.color" : "blue"}, {"shapes.$" : 1})

$slice is helpful when you know the index of the element, but sometimes you want
whichever array element matched your criteria. You can return the matching element
with the $ operator.

柏拉图鍀咏恒 2024-10-05 02:42:44
 db.getCollection('aj').find({"shapes.color":"red"},{"shapes.$":1})

输出

{

   "shapes" : [ 
       {
           "shape" : "circle",
           "color" : "red"
       }
   ]
}
 db.getCollection('aj').find({"shapes.color":"red"},{"shapes.$":1})

OUTPUTS

{

   "shapes" : [ 
       {
           "shape" : "circle",
           "color" : "red"
       }
   ]
}
逆夏时光 2024-10-05 02:42:44

mongodb 中 find 的语法是

    db.<collection name>.find(query, projection);

您编写的第二个查询,即

    db.test.find(
    {shapes: {"$elemMatch": {color: "red"}}}, 
    {"shapes.color":1})

您在查询部分使用了 $elemMatch 运算符,而如果您在投影部分使用此运算符,那么您将得到想要的结果。您可以写下您的查询,

     db.users.find(
     {"shapes.color":"red"},
     {_id:0, shapes: {$elemMatch : {color: "red"}}})

这将为您提供所需的结果。

The syntax for find in mongodb is

    db.<collection name>.find(query, projection);

and the second query that you have written, that is

    db.test.find(
    {shapes: {"$elemMatch": {color: "red"}}}, 
    {"shapes.color":1})

in this you have used the $elemMatch operator in query part, whereas if you use this operator in the projection part then you will get the desired result. You can write down your query as

     db.users.find(
     {"shapes.color":"red"},
     {_id:0, shapes: {$elemMatch : {color: "red"}}})

This will give you the desired result.

丘比特射中我 2024-10-05 02:42:44

感谢JohnnyHK

这里我只是想添加一些更复杂的用法。

// Document 
{ 
"_id" : 1
"shapes" : [
  {"shape" : "square",  "color" : "red"},
  {"shape" : "circle",  "color" : "green"}
  ] 
} 

{ 
"_id" : 2
"shapes" : [
  {"shape" : "square",  "color" : "red"},
  {"shape" : "circle",  "color" : "green"}
  ] 
} 


// The Query   
db.contents.find({
    "_id" : ObjectId(1),
    "shapes.color":"red"
},{
    "_id": 0,
    "shapes" :{
       "$elemMatch":{
           "color" : "red"
       } 
    }
}) 


//And the Result

{"shapes":[
    {
       "shape" : "square",
       "color" : "red"
    }
]}

Thanks to JohnnyHK.

Here I just want to add some more complex usage.

// Document 
{ 
"_id" : 1
"shapes" : [
  {"shape" : "square",  "color" : "red"},
  {"shape" : "circle",  "color" : "green"}
  ] 
} 

{ 
"_id" : 2
"shapes" : [
  {"shape" : "square",  "color" : "red"},
  {"shape" : "circle",  "color" : "green"}
  ] 
} 


// The Query   
db.contents.find({
    "_id" : ObjectId(1),
    "shapes.color":"red"
},{
    "_id": 0,
    "shapes" :{
       "$elemMatch":{
           "color" : "red"
       } 
    }
}) 


//And the Result

{"shapes":[
    {
       "shape" : "square",
       "color" : "red"
    }
]}
吖咩 2024-10-05 02:42:44

您只需要运行

db.test.find(
{"shapes.color": "red"}, 
{shapes: {$elemMatch: {color: "red"}}});

此查询的查询输出即可,

{
    "_id" : ObjectId("562e7c594c12942f08fe4192"),
    "shapes" : [ 
        {"shape" : "circle", "color" : "red"}
    ]
}

正如您所期望的那样,它将给出数组中与颜色匹配的确切字段:'red'。

You just need to run query

db.test.find(
{"shapes.color": "red"}, 
{shapes: {$elemMatch: {color: "red"}}});

output of this query is

{
    "_id" : ObjectId("562e7c594c12942f08fe4192"),
    "shapes" : [ 
        {"shape" : "circle", "color" : "red"}
    ]
}

as you expected it'll gives the exact field from array that matches color:'red'.

§对你不离不弃 2024-10-05 02:42:44

同样你可以找到多个

db.getCollection('localData').aggregate([
    // Get just the docs that contain a shapes element where color is 'red'
  {$match: {'shapes.color': {$in : ['red','yellow'] } }},
  {$project: {
     shapes: {$filter: {
        input: '$shapes',
        as: 'shape',
        cond: {$in: ['$shape.color', ['red', 'yellow']]}
     }}
  }}
])

Likewise you can find for the multiple

db.getCollection('localData').aggregate([
    // Get just the docs that contain a shapes element where color is 'red'
  {$match: {'shapes.color': {$in : ['red','yellow'] } }},
  {$project: {
     shapes: {$filter: {
        input: '$shapes',
        as: 'shape',
        cond: {$in: ['$shape.color', ['red', 'yellow']]}
     }}
  }}
])
哀由 2024-10-05 02:42:44

$project 一起使用会更合适,其他匹配元素将与文档中的其他元素组合在一起。

db.test.aggregate(
  { "$unwind" : "$shapes" },
  { "$match" : { "shapes.color": "red" } },
  { 
    "$project": {
      "_id":1,
      "item":1
    }
  }
)

Along with $project it will be more appropriate other wise matching elements will be clubbed together with other elements in document.

db.test.aggregate(
  { "$unwind" : "$shapes" },
  { "$match" : { "shapes.color": "red" } },
  { 
    "$project": {
      "_id":1,
      "item":1
    }
  }
)
花想c 2024-10-05 02:42:44

虽然这个问题是 9.6 年前提出的,但这对很多人都有很大的帮助,我就是其中之一。感谢大家的所有疑问、提示和回答。从这里的一个答案中选取..我发现以下方法也可以用于投影父文档中的其他字段。这可能对某人有帮助。

对于以下文档,需要查明员工(emp #7839)是否设置了 2020 年的休假历史记录。休假历史记录作为父级 Employee 文档中的嵌入文档实现。

db.employees.find( {"leave_history.calendar_year": 2020}, 
    {leave_history: {$elemMatch: {calendar_year: 2020}},empno:true,ename:true}).pretty()


{
        "_id" : ObjectId("5e907ad23997181dde06e8fc"),
        "empno" : 7839,
        "ename" : "KING",
        "mgrno" : 0,
        "hiredate" : "1990-05-09",
        "sal" : 100000,
        "deptno" : {
                "_id" : ObjectId("5e9065f53997181dde06e8f8")
        },
        "username" : "none",
        "password" : "none",
        "is_admin" : "N",
        "is_approver" : "Y",
        "is_manager" : "Y",
        "user_role" : "AP",
        "admin_approval_received" : "Y",
        "active" : "Y",
        "created_date" : "2020-04-10",
        "updated_date" : "2020-04-10",
        "application_usage_log" : [
                {
                        "logged_in_as" : "AP",
                        "log_in_date" : "2020-04-10"
                },
                {
                        "logged_in_as" : "EM",
                        "log_in_date" : ISODate("2020-04-16T07:28:11.959Z")
                }
        ],
        "leave_history" : [
                {
                        "calendar_year" : 2020,
                        "pl_used" : 0,
                        "cl_used" : 0,
                        "sl_used" : 0
                },
                {
                        "calendar_year" : 2021,
                        "pl_used" : 0,
                        "cl_used" : 0,
                        "sl_used" : 0
                }
        ]
}

Although the question was asked 9.6 years ago, this has been of immense help to numerous people, me being one of them. Thank you everyone for all your queries, hints and answers. Picking up from one of the answers here.. I found that the following method can also be used to project other fields in the parent document.This may be helpful to someone.

For the following document, the need was to find out if an employee (emp #7839) has his leave history set for the year 2020. Leave history is implemented as an embedded document within the parent Employee document.

db.employees.find( {"leave_history.calendar_year": 2020}, 
    {leave_history: {$elemMatch: {calendar_year: 2020}},empno:true,ename:true}).pretty()


{
        "_id" : ObjectId("5e907ad23997181dde06e8fc"),
        "empno" : 7839,
        "ename" : "KING",
        "mgrno" : 0,
        "hiredate" : "1990-05-09",
        "sal" : 100000,
        "deptno" : {
                "_id" : ObjectId("5e9065f53997181dde06e8f8")
        },
        "username" : "none",
        "password" : "none",
        "is_admin" : "N",
        "is_approver" : "Y",
        "is_manager" : "Y",
        "user_role" : "AP",
        "admin_approval_received" : "Y",
        "active" : "Y",
        "created_date" : "2020-04-10",
        "updated_date" : "2020-04-10",
        "application_usage_log" : [
                {
                        "logged_in_as" : "AP",
                        "log_in_date" : "2020-04-10"
                },
                {
                        "logged_in_as" : "EM",
                        "log_in_date" : ISODate("2020-04-16T07:28:11.959Z")
                }
        ],
        "leave_history" : [
                {
                        "calendar_year" : 2020,
                        "pl_used" : 0,
                        "cl_used" : 0,
                        "sl_used" : 0
                },
                {
                        "calendar_year" : 2021,
                        "pl_used" : 0,
                        "cl_used" : 0,
                        "sl_used" : 0
                }
        ]
}
鸩远一方 2024-10-05 02:42:44
db.test.find( {"shapes.color": "red"}, {_id: 0})
db.test.find( {"shapes.color": "red"}, {_id: 0})
赠我空喜 2024-10-05 02:42:44

使用聚合函数和$project获取文档中的特定对象字段

db.getCollection('geolocations').aggregate([ { $project : { geolocation : 1} } ])

结果:

{
    "_id" : ObjectId("5e3ee15968879c0d5942464b"),
    "geolocation" : [ 
        {
            "_id" : ObjectId("5e3ee3ee68879c0d5942465e"),
            "latitude" : 12.9718313,
            "longitude" : 77.593551,
            "country" : "India",
            "city" : "Chennai",
            "zipcode" : "560001",
            "streetName" : "Sidney Road",
            "countryCode" : "in",
            "ip" : "116.75.115.248",
            "date" : ISODate("2020-02-08T16:38:06.584Z")
        }
    ]
}

Use aggregation function and $project to get specific object field in document

db.getCollection('geolocations').aggregate([ { $project : { geolocation : 1} } ])

result:

{
    "_id" : ObjectId("5e3ee15968879c0d5942464b"),
    "geolocation" : [ 
        {
            "_id" : ObjectId("5e3ee3ee68879c0d5942465e"),
            "latitude" : 12.9718313,
            "longitude" : 77.593551,
            "country" : "India",
            "city" : "Chennai",
            "zipcode" : "560001",
            "streetName" : "Sidney Road",
            "countryCode" : "in",
            "ip" : "116.75.115.248",
            "date" : ISODate("2020-02-08T16:38:06.584Z")
        }
    ]
}
乖乖哒 2024-10-05 02:42:44

如果您想同时进行过滤、设置和查找

let post = await Post.findOneAndUpdate(
          {
            _id: req.params.id,
            tasks: {
              $elemMatch: {
                id: req.params.jobId,
                date,
              },
            },
          },
          {
            $set: {
              'jobs.$[i].performer': performer,
              'jobs.$[i].status': status,
              'jobs.$[i].type': type,
            },
          },
          {
            arrayFilters: [
              {
                'i.id': req.params.jobId,
              },
            ],
            new: true,
          }
        );

if you want to do filter, set and find at the same time.

let post = await Post.findOneAndUpdate(
          {
            _id: req.params.id,
            tasks: {
              $elemMatch: {
                id: req.params.jobId,
                date,
              },
            },
          },
          {
            $set: {
              'jobs.$[i].performer': performer,
              'jobs.$[i].status': status,
              'jobs.$[i].type': type,
            },
          },
          {
            arrayFilters: [
              {
                'i.id': req.params.jobId,
              },
            ],
            new: true,
          }
        );
老子叫无熙 2024-10-05 02:42:44

这个答案并没有完全回答这个问题,但它是相关的,我把它写下来,因为有人决定关闭 另一个问题将这个问题标记为重复(实际上不是)。

就我而言,我只想过滤数组元素,但仍返回数组的完整元素。以前的所有答案(包括问题中给出的解决方案)在将它们应用于我的特定情况时都让我头疼,因为:

  • 我需要我的解决方案能够返回子数组元素的多个结果
  • 使用 $unwind + $match + $group 导致丢失根文档而不匹配数组元素,在我的情况下我不想这样做因为事实上我只是想过滤掉不需要的元素。
  • 使用 $project > $filter 导致丢失其余字段或根文档,或者迫使我在投影中指定所有这些字段,这是不可取的。

所以最后我用 $addFields > 解决了所有这些问题。 $filter 像这样:

db.test.aggregate([
    { $match: { 'shapes.color': 'red' } },
    { $addFields: { 'shapes': { $filter: {
      input: '$shapes',
      as: 'shape',
      cond: { $eq: ['$shape.color', 'red'] }
    } } } },
])

说明:

  1. 首先匹配具有红色形状的文档。
  2. 对于这些文档,添加一个名为 shapes 的字段,在本例中,它将替换以相同方式调用的原始字段。
  3. 要计算 shapes 的新值,请$filter 原始 $shapes 数组的元素,暂时将每个数组元素命名为 shape 以便稍后我们可以检查 $$shape.color 是否为红色。
  4. 现在,新的 shapes 数组仅包含所需的元素。

This answer does not fully answer the question but it's related and I'm writing it down because someone decided to close another question marking this one as duplicate (which is not).

In my case I only wanted to filter the array elements but still return the full elements of the array. All previous answers (including the solution given in the question) gave me headaches when applying them to my particular case because:

  • I needed my solution to be able to return multiple results of the subarray elements.
  • Using $unwind + $match + $group resulted in losing root documents without matching array elements, which I didn't want to in my case because in fact I was only looking to filter out unwanted elements.
  • Using $project > $filter resulted in loosing the rest of the fields or the root documents or forced me to specify all of them in the projection as well which was not desirable.

So at the end I fixed all of this problems with an $addFields > $filter like this:

db.test.aggregate([
    { $match: { 'shapes.color': 'red' } },
    { $addFields: { 'shapes': { $filter: {
      input: '$shapes',
      as: 'shape',
      cond: { $eq: ['$shape.color', 'red'] }
    } } } },
])

Explanation:

  1. First match documents with a red coloured shape.
  2. For those documents, add a field called shapes, which in this case will replace the original field called the same way.
  3. To calculate the new value of shapes, $filter the elements of the original $shapes array, temporarily naming each of the array elements as shape so that later we can check if the $$shape.color is red.
  4. Now the new shapes array only contains the desired elements.
她如夕阳 2024-10-05 02:42:44

对于新版本的 MongoDB,情况略有不同。

对于db.collection.find,您可以使用find的第二个参数,键为projection

db.collection.find({}, {projection: {name: 1, email: 0}});

您还可以使用.project()方法.
然而,它不是原生的 MongoDB 方法,它是大多数 MongoDB 驱动程序(如 Mongoose、MongoDB Node.js 驱动程序等)提供的方法。

db.collection.find({}).project({name: 1, email: 0});

如果你想使用 findOne,它与 find 相同

db.collection.findOne({}, {projection: {name: 1, email: 0}});

,但是findOne 没有 .project() 方法。

For the new version of MongoDB, it's slightly different.

For db.collection.find you can use the second parameter of find with the key being projection

db.collection.find({}, {projection: {name: 1, email: 0}});

You can also use the .project() method.
However, it is not a native MongoDB method, it's a method provided by most MongoDB driver like Mongoose, MongoDB Node.js driver etc.

db.collection.find({}).project({name: 1, email: 0});

And if you want to use findOne, it's the same that with find

db.collection.findOne({}, {projection: {name: 1, email: 0}});

But findOne doesn't have a .project() method.

北方的韩爷 2024-10-05 02:42:44

有关更多详细信息,请参阅=

mongo db 官方参考

suppose you have document like this (you can have multiple document too) - 

{
  "_id": {
    "$oid": "63b5cfbfbcc3196a2a23c44b"
  },
  "results": [
    {
      "yearOfRelease": "2022",
      "imagePath": "https://upload.wikimedia.org/wikipedia/en/d/d4/The_Kashmir_Files_poster.jpg",
      "title": "The Kashmir Files",
      "overview": "Krishna endeavours to uncover the reason behind his parents' brutal killings in Kashmir. He is shocked to uncover a web of lies and conspiracies in connection with the massive genocide.",
      "originalLanguage": "hi",
      "imdbRating": "8.3",
      "isbookMark": null,
      "originCountry": "india",
      "productionHouse": [
        "Zee Studios"
      ],
      "_id": {
        "$oid": "63b5cfbfbcc3196a2a23c44c"
      }
    },
    {
      "yearOfRelease": "2022",
      "imagePath": "https://upload.wikimedia.org/wikipedia/en/a/a9/Black_Adam_%28film%29_poster.jpg",
      "title": "Black Adam",
      "overview": "In ancient Kahndaq, Teth Adam was bestowed the almighty powers of the gods. After using these powers for vengeance, he was imprisoned, becoming Black Adam. Nearly 5,000 years have passed, and Black Adam has gone from man to myth to legend. Now free, his unique form of justice, born out of rage, is challenged by modern-day heroes who form the Justice Society: Hawkman, Dr. Fate, Atom Smasher and Cyclone",
      "originalLanguage": "en",
      "imdbRating": "8.3",
      "isbookMark": null,
      "originCountry": "United States of America",
      "productionHouse": [
        "DC Comics"
      ],
      "_id": {
        "$oid": "63b5cfbfbcc3196a2a23c44d"
      }
    },
    {
      "yearOfRelease": "2022",
      "imagePath": "https://upload.wikimedia.org/wikipedia/en/0/09/The_Sea_Beast_film_poster.png",
      "title": "The Sea Beast",
      "overview": "A young girl stows away on the ship of a legendary sea monster hunter, turning his life upside down as they venture into uncharted waters.",
      "originalLanguage": "en",
      "imdbRating": "7.1",
      "isbookMark": null,
      "originCountry": "United States Canada",
      "productionHouse": [
        "Netflix Animation"
      ],
      "_id": {
        "$oid": "63b5cfbfbcc3196a2a23c44e"
      }
    },
    {
      "yearOfRelease": "2021",
      "imagePath": "https://upload.wikimedia.org/wikipedia/en/7/7d/Hum_Do_Hamare_Do_poster.jpg",
      "title": "Hum Do Hamare Do",
      "overview": "Dhruv, who grew up an orphan, is in love with a woman who wishes to marry someone with a family. In order to fulfil his lover's wish, he hires two older individuals to pose as his parents.",
      "originalLanguage": "hi",
      "imdbRating": "6.0",
      "isbookMark": null,
      "originCountry": "india",
      "productionHouse": [
        "Maddock Films"
      ],
      "_id": {
        "$oid": "63b5cfbfbcc3196a2a23c44f"
      }
    },
    {
      "yearOfRelease": "2021",
      "imagePath": "https://upload.wikimedia.org/wikipedia/en/7/74/Shang-Chi_and_the_Legend_of_the_Ten_Rings_poster.jpeg",
      "title": "Shang-Chi and the Legend of the Ten Rings",
      "overview": "Shang-Chi, a martial artist, lives a quiet life after he leaves his father and the shadowy Ten Rings organisation behind. Years later, he is forced to confront his past when the Ten Rings attack him.",
      "originalLanguage": "en",
      "imdbRating": "7.4",
      "isbookMark": null,
      "originCountry": "United States of America",
      "productionHouse": [
        "Marvel Entertainment"
      ],
      "_id": {
        "$oid": "63b5cfbfbcc3196a2a23c450"
      }
    }
  ],
  "__v": 0
}



=======


mongo db query by aggregate command - 


mongomodels.movieMainPageSchema.aggregate(
        [
            {
               $project: {
                _id:0,  // to supress id
                results: {
                     $filter: {
                        input: "$results",
                        as: "result",
                        cond: { $eq: [ "$result.yearOfRelease", "2022" ] }
                     }
                  }
               }
            }
         ]

    )
    
    
    

for more details refer =

mongo db official referance

suppose you have document like this (you can have multiple document too) - 

{
  "_id": {
    "$oid": "63b5cfbfbcc3196a2a23c44b"
  },
  "results": [
    {
      "yearOfRelease": "2022",
      "imagePath": "https://upload.wikimedia.org/wikipedia/en/d/d4/The_Kashmir_Files_poster.jpg",
      "title": "The Kashmir Files",
      "overview": "Krishna endeavours to uncover the reason behind his parents' brutal killings in Kashmir. He is shocked to uncover a web of lies and conspiracies in connection with the massive genocide.",
      "originalLanguage": "hi",
      "imdbRating": "8.3",
      "isbookMark": null,
      "originCountry": "india",
      "productionHouse": [
        "Zee Studios"
      ],
      "_id": {
        "$oid": "63b5cfbfbcc3196a2a23c44c"
      }
    },
    {
      "yearOfRelease": "2022",
      "imagePath": "https://upload.wikimedia.org/wikipedia/en/a/a9/Black_Adam_%28film%29_poster.jpg",
      "title": "Black Adam",
      "overview": "In ancient Kahndaq, Teth Adam was bestowed the almighty powers of the gods. After using these powers for vengeance, he was imprisoned, becoming Black Adam. Nearly 5,000 years have passed, and Black Adam has gone from man to myth to legend. Now free, his unique form of justice, born out of rage, is challenged by modern-day heroes who form the Justice Society: Hawkman, Dr. Fate, Atom Smasher and Cyclone",
      "originalLanguage": "en",
      "imdbRating": "8.3",
      "isbookMark": null,
      "originCountry": "United States of America",
      "productionHouse": [
        "DC Comics"
      ],
      "_id": {
        "$oid": "63b5cfbfbcc3196a2a23c44d"
      }
    },
    {
      "yearOfRelease": "2022",
      "imagePath": "https://upload.wikimedia.org/wikipedia/en/0/09/The_Sea_Beast_film_poster.png",
      "title": "The Sea Beast",
      "overview": "A young girl stows away on the ship of a legendary sea monster hunter, turning his life upside down as they venture into uncharted waters.",
      "originalLanguage": "en",
      "imdbRating": "7.1",
      "isbookMark": null,
      "originCountry": "United States Canada",
      "productionHouse": [
        "Netflix Animation"
      ],
      "_id": {
        "$oid": "63b5cfbfbcc3196a2a23c44e"
      }
    },
    {
      "yearOfRelease": "2021",
      "imagePath": "https://upload.wikimedia.org/wikipedia/en/7/7d/Hum_Do_Hamare_Do_poster.jpg",
      "title": "Hum Do Hamare Do",
      "overview": "Dhruv, who grew up an orphan, is in love with a woman who wishes to marry someone with a family. In order to fulfil his lover's wish, he hires two older individuals to pose as his parents.",
      "originalLanguage": "hi",
      "imdbRating": "6.0",
      "isbookMark": null,
      "originCountry": "india",
      "productionHouse": [
        "Maddock Films"
      ],
      "_id": {
        "$oid": "63b5cfbfbcc3196a2a23c44f"
      }
    },
    {
      "yearOfRelease": "2021",
      "imagePath": "https://upload.wikimedia.org/wikipedia/en/7/74/Shang-Chi_and_the_Legend_of_the_Ten_Rings_poster.jpeg",
      "title": "Shang-Chi and the Legend of the Ten Rings",
      "overview": "Shang-Chi, a martial artist, lives a quiet life after he leaves his father and the shadowy Ten Rings organisation behind. Years later, he is forced to confront his past when the Ten Rings attack him.",
      "originalLanguage": "en",
      "imdbRating": "7.4",
      "isbookMark": null,
      "originCountry": "United States of America",
      "productionHouse": [
        "Marvel Entertainment"
      ],
      "_id": {
        "$oid": "63b5cfbfbcc3196a2a23c450"
      }
    }
  ],
  "__v": 0
}



=======


mongo db query by aggregate command - 


mongomodels.movieMainPageSchema.aggregate(
        [
            {
               $project: {
                _id:0,  // to supress id
                results: {
                     $filter: {
                        input: "$results",
                        as: "result",
                        cond: { $eq: [ "$result.yearOfRelease", "2022" ] }
                     }
                  }
               }
            }
         ]

    )
    
    
    

野心澎湃 2024-10-05 02:42:44

如果您想返回第一个匹配的形状find()就能解决问题(如此处详述),但如果您想返回与原始文档匹配的每个形状,您可以执行以下聚合

db.collection.aggregate([
  {
    $set: {
      shapes: {
        $filter: {
          input: "$shapes",
          as: "shape",
          cond: {$eq: ["$shape.color", "red"]}
        }
      }
    }
  },
  {
    $match: {
      $nor: [
        {shapes: {$exists: false}},
        {shapes: {$size: 0}}
      ]
    }
  }
])

使用它在 mongo 游乐场。这是过滤 shapes 属性并保留其他属性(而不是使用 $project 删除其他属性,并且需要额外的步骤来获取文档)。

附加的 $match 是可选的,它会删除具有空 shapes 数组的文档。

If you want to return the first matching shapes, find() will do the trick (as detailed here), but if you want to return every matching shapes with the original document you can do the following aggregate:

db.collection.aggregate([
  {
    $set: {
      shapes: {
        $filter: {
          input: "$shapes",
          as: "shape",
          cond: {$eq: ["$shape.color", "red"]}
        }
      }
    }
  },
  {
    $match: {
      $nor: [
        {shapes: {$exists: false}},
        {shapes: {$size: 0}}
      ]
    }
  }
])

Play with it in mongo playground. This is filtering the shapes attribute in place and keeping the others (instead of using $project which remove others attributes, and need an extra step to get the doc back).

The additional $match is optionnal, it removes documents with empty shapes array.

二智少女猫性小仙女 2024-10-05 02:42:44
    db.collection.aggregate([
      {
        "$unwind": "$shapes"
      },
      {
        "$match": {
          "$and": [
            {
              "shapes.color": "red"
            },
            {
              "shapes.shape": "circle"
            }
          ]
        }
      },
      //remove objectid
      {
        "$project": {
          _id: 0
        }
      }
    ])
    db.collection.aggregate([
      {
        "$unwind": "$shapes"
      },
      {
        "$match": {
          "$and": [
            {
              "shapes.color": "red"
            },
            {
              "shapes.shape": "circle"
            }
          ]
        }
      },
      //remove objectid
      {
        "$project": {
          _id: 0
        }
      }
    ])
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文