Suppose I have:
Order: {_id: ..., items: [...]}
How to filter orders which have item number greater than 5?
You cann't query by size of embed collection, you need to create field with size of collection for such needs(mongo db documentation):
The $size operator matches any array with the specified number of elements. The following example would match the object {a:["foo"]}, since that array has just one element:
db.things.find( { a : { $size: 1 } } );
You cannot use $size to find a range of sizes (for example: arrays with more than 1 element). If you need to query for a range, create an extra size field that you increment when you add elements.
You can use the $where operator.
> db.orders.save({Order: {items: [1,2]}})
> db.orders.save({Order: {items: [1,2,3]}})
> db.orders.find({$where:function() { if (this["Order"]["items"].length > 2) return true; }})
{ "_id" : ObjectId("4d334c9102bcfe450ce52585"), "Order" : { "items" : [ 1, 2, 3 ] } }
Two downsides of $where are that it can't use an index and the BSON object must be converted to a JavaScript object, since you are running a custom JavaScript function on every document in the collection.
So, $where can be very slow for large collections. But, for ad hoc or rarely run queries, it's extremely handy. If you frequently need to run queries like this, then you should follow Bugai13's recommendation, since you can then index the key in which you store the array size.
To see if the length is greater than 5, you can test if a 6th element exists:
db.orders.find({"items.6": {$exists: true}})
This is much more efficient than using $where
.
I too faced this dilemma. Not sure why it doesnt exist in MongoDB by default. The most efficient way is to also store a property called count
or length
or something that denotes how many items are in the array.
Then you can index that property and do range queries on it. It'll keep your queries simple and quick.
Just make sure that your application keeps it in sync.