假设我的收藏中有以下文件:

{  
   "_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})

Or

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

返回匹配的文档(文档1),但总是使用形状中的ALL数组项:

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

但是,我想只获得包含color=red的数组的文档(文档1):

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

我该怎么做呢?


当前回答

MongoDB 2.2+中的新的聚合框架为Map/Reduce提供了一种替代方案。$unwind操作符可以用来将你的形状数组分离成一个可以匹配的文档流:

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
}

其他回答

感谢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"
    }
]}

更多细节请参考=

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" ] } } } } } ] )

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

对于下面的文档,需要查明员工(emp #7839)是否将其休假历史设置为2020年。休假历史记录被实现为父雇员文档中的嵌入式文档。

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
                }
        ]
}

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

在我的例子中,我只想过滤数组元素,但仍然返回数组的完整元素。所有之前的答案(包括问题中给出的解决方案)在应用到我的特定情况时都让我头疼,因为:

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

所以在最后,我用$addFields > $过滤器修复了所有这些问题:

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

解释:

首先将文件与红色形状匹配。 对于这些文档,添加一个名为shapes的字段,在本例中,它将以同样的方式替换原来的字段。 要计算形状的新值,$filter原始$shapes数组的元素,临时将每个数组元素命名为shape,以便稍后可以检查$$shape。颜色是红色。 现在,新的形状数组只包含所需的元素。

与$project一起,其他明智的匹配元素将与文档中的其他元素组合在一起。

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