|
|
Unlike relational database models, MongoDB documents can have fields which have values as arrays. The prototypical example in almost all MongoDB documentation is a document having a tags field, whose value is an array of strings, such as ["NoSQL", "Ruby", "MongoDB"]. If you’re coming from a relational world (which most of us are) then this feature, at first glance, is a bit intimidating.
For instance, most queries, regardless of the underlying data structure (be it a relational table, JSON document, dictionary, etc) target a value and not the key itself. Using the aforementioned document containing a tags field with an array as its value, there isn’t much value in querying on the key tags — queries target a key’s value(s). So in this case, the questions asked are in the form of “what documents contain the tag X”, which is easy enough of conceptualize when the value is singular (i.e. select * from document where tag = X).
Yet, when a key’s value is pluralized as in the case above, I sometimes find myself wondering how to construct a query when I only know a portion of the available values. For example, here’s a simple document with two fields:
{a:"foo", b:[10,20,30]}
In this case, the field b has an array of numbers as values. I’m going to add this document along with a few others to a Mongo collection dubbed foo_test.
> db.foo_test.save({a:"foo", b:[10,20,30]})
> db.foo_test.save({a:"foo", b:[15,25,35]})
> db.foo_test.save({a:"foo", b:[10,40,50]})
> db.foo_test.save({a:"bar", b:[10,60,70]})
With those documents created, the question becomes, how do you find all documents who have a 10 in their b‘s values?
Because it’s Mongo’s bag, baby, it turns out to be effortlessly simple. Just query for the value as if it were singular!
> db.foo_test.find({"b":10})
{ "_id" : ObjectId("4dd56bc747cc1d1360674d73"), "a" : "foo", "b" : [ 10, 20, 30 ] }
{ "_id" : ObjectId("4dd56be347cc1d1360674d75"), "a" : "foo", "b" : [ 10, 40, 50 ] }
{ "_id" : ObjectId("4dd56bee47cc1d1360674d76"), "a" : "bar", "b" : [ 10, 60, 70 ] }
What if you want a bit more finesse, such as finding the distinct values of a where b has the value 10? Just as easy, baby.
> db.foo_test.distinct("a", {"b":10})
[ "bar", "foo" ]
One thing to note: you can, and probably should (if you plan to search on array values a lot and there are going to be a lot of documents) add an index to b. While this might slow down inserts (as the index will need updating each time) it’ll most likely improve reads.
> db.foo_test.ensureIndex({b:1})
Arrays as values in a MongoDB document might look odd when you find yourself thinking of how to query against them. But as it turns out, they aren’t so bad and you can act against them as if they were a single value. Not bad if you ask me.