Aggregation matching documents with array size

6,934 views
Skip to first unread message

rawc0der

unread,
Feb 12, 2014, 6:45:06 AM2/12/14
to mongod...@googlegroups.com
Hello everybody,

I'm trying to aggregate results from a collection where one of the fields is an Array and I'm particularly interested in those results with size greater than 2.
It could have been pretty simple to use something like:
collection.aggregate([
 
{$match: {'ArrayField': {$size: {$gt: 2} } } },
 
{$unwind: '$ArrayField' },
 
function(err, results){
   
// always returns []
 
}
]);

Also native implementation of the aggregation pipeline doesn't allow to use $where in $match queries. so I can't use the expression 
{$where: 'this.ArrayField.length > 2'}

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
I found a workaround that fits my design logic using the $or operator, but this has limited use cases.  
The code:
collection.aggregate([
 
{$match: {$or: [
    {'ArrayField': {$size: 2 } },
   
{'ArrayField': {$size: 3 } },
   
// and so on
 
] } },
 
{$unwind: '$ArrayField' },
 
function(err, results){
   
// this works, but it's hard to adapt to a situation where the array size can be between 2 and let's say .. 10
 
}
])

If anybody has a suggestion, I'm open for ideas.
Thanks.

Robert Stam

unread,
Feb 12, 2014, 9:42:35 AM2/12/14
to mongod...@googlegroups.com
There is no query operator that lets you directly test for the size of an array field being greater than some value, but a trick I've seen used before is to test for the existence of an array element to deduce information about the length of an array field. For example, all array fields of length > 2 would have an a[2] element.

So for example (using the mongo shell), you could use the following match in an aggregation framework pipeline to match documents where the ArrayField has more than 2 items:

> db.test.find()
{ "_id" : ObjectId("52fb86625efdab38f160760b") }
{ "_id" : ObjectId("52fb86685efdab38f160760c"), "ArrayField" : null }
{ "_id" : ObjectId("52fb866b5efdab38f160760d"), "ArrayField" : [ ] }
{ "_id" : ObjectId("52fb86735efdab38f160760e"), "ArrayField" : [ 0 ] }
{ "_id" : ObjectId("52fb86765efdab38f160760f"), "ArrayField" : [ 0, 1 ] }
{ "_id" : ObjectId("52fb86795efdab38f1607610"), "ArrayField" : [ 0, 1, 2 ] }
{ "_id" : ObjectId("52fb867c5efdab38f1607611"), "ArrayField" : [ 0, 1, 2, 3 ] }
>
> db.test.aggregate({ $match : { "ArrayField.2" : { $exists : true } } })
{ "_id" : ObjectId("52fb86795efdab38f1607610"), "ArrayField" : [ 0, 1, 2 ] }
{ "_id" : ObjectId("52fb867c5efdab38f1607611"), "ArrayField" : [ 0, 1, 2, 3 ] }
>



--
--
You received this message because you are subscribed to the Google
Groups "mongodb-user" group.
To post to this group, send email to mongod...@googlegroups.com
To unsubscribe from this group, send email to
mongodb-user...@googlegroups.com
See also the IRC channel -- freenode.net#mongodb
 
---
You received this message because you are subscribed to the Google Groups "mongodb-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mongodb-user...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Asya Kamsky

unread,
Feb 14, 2014, 5:55:33 AM2/14/14
to mongodb-user
The "array.x":{$exists:true} trick works but more good news is that in 2.6 the aggregation framework will allow you to project the size of the array as a new field in the document which means you'll be able to filter on it as well.

Asya

Reply all
Reply to author
Forward
0 new messages