72

I have a collection where every document in the collection has an array named foo that contains a set of embedded documents. Is there currently a trivial way in the MongoDB shell to count how many instances are within foo? something like:

db.mycollection.foos.count() or db.mycollection.foos.size()?

Each document in the array needs to have a unique foo_id and I want to do a quick count to make sure that the right amount of elements are inside of an array for a random document in the collection.

3 Answers 3

109

In MongoDB 2.6, the Aggregation Framework has a new array $size operator you can use:

> db.mycollection.insert({'foo':[1,2,3,4]})
> db.mycollection.insert({'foo':[5,6,7]})

> db.mycollection.aggregate([{$project: { count: { $size:"$foo" }}}])
{ "_id" : ObjectId("5314b5c360477752b449eedf"), "count" : 4 }
{ "_id" : ObjectId("5314b5c860477752b449eee0"), "count" : 3 }
Sign up to request clarification or add additional context in comments.

9 Comments

Are there any way that we can get 7 (4+3) in this case?
@xxbidiao Sure, just use a $group stage which sums up the array sizes: db.mycollection.aggregate({$group: { _id: null, totalSize: { $sum: { $size: "$foo"}} }}).
I had to put [ ] around {$project: { count: { $size:"$foo" }}} for it to work, see github.com/Studio3T/robomongo/issues/…
@Max I'd also suggest looking for a more actively updated tool than Robo3T. Each Robo3T release embeds a specific version of the mongo shell which may cause unexpected issues when used with mismatched MongoDB server release versions (for example, significantly older or newer). Most admin tools use the MongoDB API for broader cross-version compatibility. MongoDB Compass is free and supported by the MongoDB team, but there are many alternatives depending on your requirements.
@datdinhquoc You can add an initial $match stage to your aggregation pipeline to filter documents before applying the projection. Without any other stages, this aggregation query would process all documents in the collection. Modern versions of MongoDB (3.4+) also have an $addFields stage which can be useful to create output including existing fields from the input documents as well as newly added fields like a count of array items.
|
34

if you are on a recent version of mongo (2.2 and later) you can use the aggregation framework.

db.mycollection.aggregate([
  {$unwind: '$foo'},
  {$group: {_id: '$_id', 'sum': { $sum: 1}}},
  {$group: {_id: null, total_sum: {'$sum': '$sum'}}}
])

which will give you the total foos of your collection.

Omitting the last group will aggregate results per record.

1 Comment

Awesome, helped me as well. Can you suggest how can I have an access to "total_sum" in further calculations?
7

Using Projections and Groups

db.mycollection.aggregate(
    [
        {
            $project: {
                _id:0,
                foo_count:{$size:"$foo"},
            }
        }, 
        {
            $group: {
                foo_total:{$sum:"$foo_count"},
            }
        }
    ]
)

Multiple child array counts can also be calculated this way

db.mycollection.aggregate(
    [
        {
            $project: {
                _id:0,
                foo1_count:{$size:"$foo1"},
                foo2_count:{$size:"$foo2"},
            }
        }, 
        {
            $group: {
                foo1_total:{$sum:"$foo1_count"},
                foo2_total:{$sum:"$foo2_count"},
            }
        }
    ]
)

2 Comments

anyway to protect if the array is missing in a document?
@chovy I know you probably no longer need this, but you can add foo1:{$type:"array"} in the $match stage.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.