使用单个查询从嵌套数组中排除子文档

时间:2014-11-30 17:02:43

标签: mongodb

我有一个包含以下结构文档的集合:

{
    "_id" : ObjectId("547b4b4ba7d3aef3bdbc5e1c"),
    "title" : "article1",
    "comments" : [
        {
            "text" : "first comment",
            "createdAt" : ISODate("2014-11-30T16:52:24.032Z")
        }
    ],
    "pictures" : [
        {
            "url" : "http://example.com/1.jpg",
            "isPrimary" : false
        },
        {
            "url" : "http:example.com/2.jpg",
            "isPrimary" : true
        },
        {
            "url" : "http://example.com/3.jpg"
        }
    ]
}

我需要使用单个查询提取所有文档并排除非主要图片。即输出应该是:

{
    "_id" : ObjectId("547b4b4ba7d3aef3bdbc5e1c"),
    "title" : "article1",
    "comments" : [
        {
            "text" : "first comment",
            "createdAt" : ISODate("2014-11-30T16:52:24.032Z")
        }
    ],
    "pictures" : [
        {
            "url" : "http:example.com/2.jpg",
            "isPrimary" : true
        }
    ]
}

如果"图片"甚至更好将包含文档而不是数组:

...
"pictures" : {
    "url" : "http:example.com/2.jpg",
    "isPrimary" : true
}
...

我尝试了聚合和$ redact,但它不起作用,因为文档和评论子文档没有' isPrimary'字段。

1 个答案:

答案 0 :(得分:0)

Aggregation Framework中使用$unwind

db.collection.aggregate([
 { $project: {
     _id: 1,
     title: 1,
     comments: 1,
     pictures:  { 
         $cond : [ 
            // if pictures is null or does not exists, project it to []
            {  $eq : [ { $ifNull: [ "$pictures", [] ] } , [] ] },
            // if pictures is [] then project it to a list with one fake empty picture with isPrimary set to true 
            [  { isPrimary: true, _empty: true }  ], 
            // otherwise project it to just the original pictures property
            "$pictures"
         ] } 
 } },
 { $unwind: "$pictures" },
 { $match: { "pictures.isPrimary": true } },
 { $group: {
     _id: "$_id",
     title: { $first: "$title" },
     comments: { $first: "$comments" },
     picture: { $first: "$pictures" }
 } },
 { $project: {
    _id: 1,
     title: 1,
     comments: 1,
     // filter out the fake isPrimary pictures that were added in the initial projection
     picture: { $cond: [ { $eq: [ "$picture._empty", true ] }, {}, "$picture" ] }
 } }
])