In modern versions of MongoDB, the most efficient way is to simply label the array using existing document properties. Direct array writing was introduced in MongoDB 3.2:
db.collection.aggregate([ { "$project": { "lat": 1, "long": 1, "geometry": { "type": { "$literal": "Point" }, "coordinates": [ "$lat", "$long" ] } }}, { "$out": "newcollection" } ])
Or even using $addFields to simply “add” a new property to documents:
db.collection.aggregate([ { "$addFields": { "geometry": { "type": { "$literal": "Point" }, "coordinates": [ "$lat", "$long" ] } }}, { "$out": "newcollection" } ])
If you are using MongoDB 2.6 and above, you can do this using the aggregation structure and avoid looping results in your client program to create a new collection.
The main feature here is that it will help you $out operator to send output to a new collection. But also be a little smart to create the array you need.
db.collection.aggregate([ { "$project": { "lat": 1, "long": 1, "type": { "$literal": ["lat","long"] } }}, { "$unwind": "$type" }, { "$group": { "_id": "$_id", "lat": { "$first": "$lat" }, "long": { "$first": "$long" }, "coordinates": { "$push": { "$cond": [ { "$eq": [ "$type", "lat" ] }, "$lat", "$long" ] } } }}, { "$project": { "lat": 1, "long": 1, "geometry": { "type": { "$literal": "Point" }, "coordinates": "$coordinates" } }}, { "$out": "newcollection" } ])
Thus, it uses the $literal operator to indicate a new array at the head of the pipeline. This statement will place the content in the document property exactly how it will be delivered. Therefore, no variables are allowed, therefore "literal".
To create an array of "coordintes", we simply unwrap the first array, which essentially creates two of each document with a different value in the "type". It is then used in $group to conditionally $push either the value of "$ lat" or "$ long" for this array.
Finally, use $project again to complete the structure of the document, and then $out sends all the output to the new collection.
Please note that this only makes sense if you intend to create a new collection and not send traffic "over the wire." This cannot be used solely within the aggregation framework to reorganize your document with the intention of then executing a “geospatial” query in the same aggregation pipeline, since “geospatial” queries will only work if the collection is actually indexed.
Thus, this can help you create a new collection of your choice, but at least it serves as an example (or two examples in fact) of how to create an array of different values using an aggregation structure.