简体   繁体   中英

exclude subdocuments from nested array using single query

I have a collection that contains docs of following structure:

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

I need to pull all documents and exclude non-primary pictures using single query. Ie output should be:

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

Or even better if "pictures" will contains document instead of array:

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

I tried aggregate and $redact, but it doesn't work because the document and the comments sub-doc don't have 'isPrimary' field.

Use $unwind in Aggregation Framework :

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM