6

I've got a collection were documents have nested arrays, and I would like to select only the lower arrays, is it possible?

I have tried this but it doesn't work:

db.collection.find({},{'family.children.$.toys' :1})

document example

   {
    "id":1000,
    "name": "Bob",
    "surname":"The Builder",
    "family":{
        "size":2,
        "status": "happy",
        "children":[{
            "name":"Jim",
            "school": "St. Mary",
            "toys":[{
                "name":"Lego"
            },
            {
                "name":"Playstation"
            }]
        },
        {
            "name":"Kate",
            "school": "St. Mary",
            "toys":[{
                "name":"Xbox"
            },
            {
                "name":"Barbie"
            }]
        }
        ]
    }
}

Expected result (extract only toys list):

{
_id:1000,
family:{
    childrens:[{
        toys:[{
            name:Lego
        },
        {
            name:Playstation
        }]
    },
    {
        toys:[{
            name:Xbox,
        },
        {
            name:Barbie
        }]
    }
    ]
}}
Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
MQ87
  • 1,008
  • 1
  • 13
  • 30
  • One approach would be to use the aggregation framework. I think that would be actually a typical use case for it. The following post will probably guide you a bit more in the direction of a possible solution: http://stackoverflow.com/questions/15117030/how-to-filter-array-in-subdocument-with-mongodb – Matthias Sep 22 '15 at 15:11
  • 1
    Can you at least try to post valid JSON data? – styvane Sep 22 '15 at 15:14
  • He only needs $project from the aggregation framework, which is also available for find(). – Cetin Basoz Sep 22 '15 at 15:18
  • @user3100115 Now it should be ok – MQ87 Sep 22 '15 at 15:28

2 Answers2

13
db.collection.find({},{'id':1, 'family.children.toys' :1, '_id':0})

Sample output:

{
        "id" : 1000,
        "family" : {
                "children" : [
                        {
                                "toys" : [
                                        {
                                                "name" : "Lego"
                                        },
                                        {
                                                "name" : "Playstation"
                                        }
                                ]
                        },
                        {
                                "toys" : [
                                        {
                                                "name" : "Xbox"
                                        },
                                        {
                                                "name" : "Barbie"
                                        }
                                ]
                        }
                ]
        }
}
Cetin Basoz
  • 22,495
  • 3
  • 31
  • 39
  • This works, and it was pretty simple! I was sure that I had already tried it, so I posted the question :D. Thanks – MQ87 Sep 22 '15 at 15:33
1

You can also do this with aggregation. You use the $map operator to return only the toys field.

db.collection.aggregate([{ 
    "$project": { 
        "family.childrens": { 
            "$map": { 
                "input": "$family.children",
                "as": "f", 
                "in": { "toys": "$$f.toys" }
            }
        }
     }}
 ])
styvane
  • 59,869
  • 19
  • 150
  • 156
  • The accepted answer looks more direct, there is any performance reason why we should use this aggregation framework version? – MQ87 Sep 22 '15 at 15:46
  • 1
    @MQ87 No the accepted answer is the best way to do this here(I even upvoted the answer). I added this answer so you know because sometimes aggregation is the only way. – styvane Sep 22 '15 at 16:05