One of the most disappointing things about Aggregation Framework in MongoDB is that it doesn't give you many ways to figure out dynamically what schema you are working with. There's the expected '$ifNull' operator, since many fields might show up only in some documents, but I wish there was a simple way to tell if something is or isn't an array.
It turns out there is a "stupid trick" for that. You can use "$project" stage to output a new field which tells you whether or not another field is an array like this:
It turns out there is a "stupid trick" for that. You can use "$project" stage to output a new field which tells you whether or not another field is an array like this:
This isn't strictly "kosher" but it works in 2.4 and in upcoming 2.6 so I'm going to keep using it - hopefully by the time it stops working, a real operator to project type may be available.
What's the point of doing this, other than just "for fun"? Well, it turns out there are some operators which only work on arrays and if you try to use them on non-arrays you will get an error. One of them in "$unwind" stage, another is the new in 2.6 "$size" operator which returns the size of an array field, but gives an error if the field is not an array.
What's the point of doing this, other than just "for fun"? Well, it turns out there are some operators which only work on arrays and if you try to use them on non-arrays you will get an error. One of them in "$unwind" stage, another is the new in 2.6 "$size" operator which returns the size of an array field, but gives an error if the field is not an array.
We took an assortment of documents which had tags field as an array sometimes, as non-array of different types sometimes, and absent some of the times. The projection we created outputs the size of the field tags in every case, where if the field is null, absent or a non-array we output size 'null' and in all other cases we output the actual size of the array.
Of course the '$size' operator is quite handy in much simpler scenarios where you might be creating an array of unique values during a '$group' stage using'$addToSet' and then you can use '$size' to find out how many unique values ended up being accumulated in that array.
For those looking forward to other new features of aggregation in 2.6 I figured I'd show an alternate way to do this with only a single "$project" stage, instead of three in sequence above:
Of course the '$size' operator is quite handy in much simpler scenarios where you might be creating an array of unique values during a '$group' stage using'$addToSet' and then you can use '$size' to find out how many unique values ended up being accumulated in that array.
For those looking forward to other new features of aggregation in 2.6 I figured I'd show an alternate way to do this with only a single "$project" stage, instead of three in sequence above:
Here, I'm using the new in 2.6 "$let" expression, which allows me to create a named variable "isArray" which I later reference using "$$isArray" syntax. Note that I'm also using the new in 2.6 "$cond" syntax which lets me use a document with "if", "then", and "else" field names, hopefully making it more readable than just using an array of three expressions (which is still supported so that you don't have to rewrite your existing aggregations).
I hope you enjoy some of the new 2.6 aggregation enhancements - I will probably continue writing about them, as they make some of our old tricks unnecessary, but open the door to a whole new set of tricks to come!
I hope you enjoy some of the new 2.6 aggregation enhancements - I will probably continue writing about them, as they make some of our old tricks unnecessary, but open the door to a whole new set of tricks to come!