Sam Delaney
Sam Delaney

Reputation: 335

Retrieve a subdocument from Mongodb

I have no code to show as I do not know how to achieve what I want.

I have read that it is possible to return a sub document from a document, but I have not found out how to actually do this. A contrived example of a Users collection:

[
   {
      "_id":0,
      "Name":"Person 1",
      "Cupboard":[
         {
            "_id":0,
            "Items":[
               {
                  "_id":1,
                  "Name":"item 1"
               },
               {
                  "_id":2,
                  "Name":"item 2"
               }
            ]
         }
      ]
   }
    ,
    {
      "_id":1,
      "Name":"Person 2",
      "Cupboard":[
         {
            "_id":0,
            "Items":[
               {
                  "_id":1,
                  "Name":"item 1"
               },
               {
                  "_id":2,
                  "Name":"item 2"
               }
            ]
         }
      ]
   }
]  

How do I ONLY return Items from a cupboard, assuming I know the cupboard's _id? I am using the C# driver, but even help doing it in the mongo shell would be useful.

Upvotes: 1

Views: 1948

Answers (3)

Kevin Smith
Kevin Smith

Reputation: 14436

You could do something like

> db.users.find({"Cupboard._id": 0}, {"Cupboard.$" : 1}).pretty()

Which will return

{
        "_id" : 0,
        "Cupboard" : [
                {
                        "_id" : 0,
                        "Items" : [
                                {
                                        "_id" : 1,
                                        "Name" : "item 1"
                                },
                                {
                                        "_id" : 2,
                                        "Name" : "item 2"
                                }
                        ]
                }
        ]
}
{
        "_id" : 1,
        "Cupboard" : [
                {
                        "_id" : 0,
                        "Items" : [
                                {
                                        "_id" : 1,
                                        "Name" : "item 1"
                                },
                                {
                                        "_id" : 2,
                                        "Name" : "item 2"
                                }
                        ]
                }
        ]
}
>

However lets change our documents around so that we have the following, so that our users ahve multiple cupboards and some diffrent items in them too

> db.users.find().pretty()
{
        "_id" : 0,
        "Name" : "Person 1",
        "Cupboard" : [
                {
                        "_id" : 0,
                        "Items" : [
                                {
                                        "_id" : 1,
                                        "Name" : "item 1"
                                },
                                {
                                        "_id" : 2,
                                        "Name" : "item 2"
                                }
                        ]
                },
                {
                        "_id" : 1,
                        "Items" : [
                                {
                                        "_id" : 1,
                                        "Name" : "item 1"
                                },
                                {
                                        "_id" : 2,
                                        "Name" : "item 2"
                                }
                        ]
                }
        ]
}
{
        "_id" : 1,
        "Name" : "Person 2",
        "Cupboard" : [
                {
                        "_id" : 0,
                        "Items" : [
                                {
                                        "_id" : 1,
                                        "Name" : "item 1"
                                },
                                {
                                        "_id" : 2,
                                        "Name" : "item 2"
                                }
                        ]
                },
                {
                        "_id" : 2,
                        "Items" : [
                                {
                                        "_id" : 21,
                                        "Name" : "item 1"
                                },
                                {
                                        "_id" : 22,
                                        "Name" : "item 2"
                                }
                        ]
                }
        ]
}

We can now list all cupboards by user.

db.users.aggregate([
    {$match: {"Cupboard._id": 0}},
    {$project: {"Cupboard._id": 1}}
])

{ "_id" : 0, "Cupboard" : [ { "_id" : 0 }, { "_id" : 1 } ] }
{ "_id" : 1, "Cupboard" : [ { "_id" : 0 }, { "_id" : 2 } ] }

Upvotes: 1

sambomartin
sambomartin

Reputation: 6813

If you want to return many Items you can use the aggregation framework's $unwind to project the child items as the result of the query.

http://docs.mongodb.org/manual/reference/aggregation/unwind/

Then use $project to return the results of the Items

Make sure you filter results early in the pipeline using $match operator to make use of indexes.

You can create a pipeline as a BsonDocument. Here's an example:

var match = new BsonDocument 
            { 
                { 
                    "$match", 
                    new BsonDocument 
                        { 
                            {"Cupboard.Items._id", 123} 
                        } 
                } 
            };

var match2 = new BsonDocument 
            { 
                /* other pipeline op */
            };

var pipeline = new[] { match, match2 };
var result = coll.Aggregate(pipeline);

If however you want to return the User documents (or part of) where a child Item matches specific criteria you can simple use find.

db.Users.find({'Cupboard.Items._id':1234})

Hope that helps

Upvotes: 1

Miguel Cartagena
Miguel Cartagena

Reputation: 2606

All you need to do is project only the fields that you want. So on your dataset, return only items from cupboard will be:

db.collection.find({ ... }, { 'Cupboard.Items' : 1, _id : 0 })

Upvotes: 2

Related Questions