It can be useful to determine what data type a particular field is during aggregation. It's most useful to determine whether something is an array or not - mainly so that you don't try to get its $size, for example, but it can be useful for other types - you may need to apply some sort of transformation, or conversion before the next stage.
Aggregation does not (yet) have a $typeOf expression, otherwise you could just $project a new field with {"$typeOf" : "$field"} as its value. So we have to be more tricky and starting with MongoDB 3.0 we can be, due to SERVER-3304 which ensures consistent total ordering across all different types.
The ordering is documented and you can always double-check the source code just to be sure.
Let's look at an example collection:
Aggregation does not (yet) have a $typeOf expression, otherwise you could just $project a new field with {"$typeOf" : "$field"} as its value. So we have to be more tricky and starting with MongoDB 3.0 we can be, due to SERVER-3304 which ensures consistent total ordering across all different types.
The ordering is documented and you can always double-check the source code just to be sure.
Let's look at an example collection:
How can we create an aggregation to output the type of each "f1" value? One thing that will help in the future will be the $isArray operator coming in 3.2 (now available as part of development version 3.1.5), but we don't really need it here. Knowing the total ordering across all types, we can figure out each type by comparing the value to lowest possible value of that data type, ordering the comparisons in such a way as to always get at most one type.
Because we don't want to write out long "if then else" type conditions, let's generate them in the mongo shell with a function:
Because we don't want to write out long "if then else" type conditions, let's generate them in the mongo shell with a function:
When we include a call to this function with a string representing value of a field, it generates a very long string of "$cond" "if:, then:, else:" tests, which gives us a type. Let's now include it in our aggregation call and check out the results:
The $project stage passed through _id (default) and "f1" plus we added a new field "typeF1" which was equal to the long and nested conditional generated by getTypes js function we just created.
Until SERVER-13447 gives us an operator/expression to get the same value simply, this will work just fine.
Until SERVER-13447 gives us an operator/expression to get the same value simply, this will work just fine.