Christopher Holmok
Christopher Holmok

Reputation: 91

Getting counts of embedded collections in a MongoDB Document

I am using MongoDB and the 10Gen node.js driver.

I have a collection in MongoDB that has docs similar to this:

{
 _id: ObjectId( "500310affdc47af710000001" ),
 name:'something',
 tags:['apple','fruit','red'],
 created: Date( 1342378221351 )
}

What I would like to get is look at all the documents and get a distinct count of all tags across all documents in the collection. I tried the group function and got this:

> db.photos.group(
... {cond:{}
... ,key:{tags:true}
... ,initial:{count:0}
... ,reduce:function(doc,out){out.count++}
... ,finalize:function(out){}});
[
    {
        "tags" : null,
        "count" : 35
    },
    {
        "tags" : [
            "#strawberry",
            "#friutpicture"
        ],
        "count" : 1
    }
]

Which is not right. I can get the distinct without the counts like this:

> db.photos.distinct('tags')
[
    "#friutpicture",
    "#strawberry",
    "#factory",
    "#wallpaper",
    "#bummber",
    "#test",
    "#fire",
    "#watermark"
]

but I need the counts.

Upvotes: 2

Views: 2140

Answers (1)

Asya Kamsky
Asya Kamsky

Reputation: 42352

You can use the following in the new Aggregation Framework (2.1+):

> db.photos..aggregate([{$unwind:"$tags"},
                        {$group:{_id:"$tags"}},
                        {$group:{_id:"DistictCount",count:{$sum:1}}}])

Your result will be:

{
    "result" : [
        {
            "_id" : "DistictCount",
            "count" : 8
        }
    ],
    "ok" : 1
}

The group function won't do what you need because you need to "unroll" the tag array before you can group on it and that means you need a map function that emits each tag in a document, as well as a reduce. You can use map/reduce if you are stuck on 2.0 or earlier and can't use aggregation framework. Here is an example that may help.

Upvotes: 5

Related Questions