How to create a new array field with a general structure

I am starting to use mongoDb and I am stuck in a simple case.

Say I have a 'aCollection' collection with elements such as:

{ _id: ObjectId(123), lat: 48,56623, long: 2,56332 } 

and I want to create a new collection with these elements:

 { _id: ObjectId(123), lat: 48,56623, long: 2,56332, geometry : { type: "Point", coordinates: [48,56623, 2,56332] } } 

I was thinking about the aggregation structure:

 db.aCollection.aggregate([{$project: { _id: 1, lat: 1, long: 1, geometry: { type: {$concat: ["Point"]}, coordinates: ["$lat", "$long"] } }}]) 

But it does not work, and I get this exception:

"exception: illegal Array field type in the object expression (in 'coordinates')"

The following aggregation works, but it does not produce the expected result:

 db.aCollection.aggregate([{$project: { _id: 1, lat: 1, long: 1, geometry: { type: {$concat: ["Point"]}, coordinates: "$lat" } }}]) 

How do you start creating this collection? 1) with an aggregation structure 2) without an aggregation structure

thanks

+6
source share
4 answers

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.

+8
source

You do not need an aggregation function for this. A find , forEach and insert are one potential approach:

 db.aCollection.find().forEach( function(myDoc) { myDoc.geometry = {type: "Point", coordinates: [myDoc.lat, myDoc.long]}; db.newCollection.insert(myDoc); }); 

It causes a separate insert for each document, but quickly and dirty if you have a small collection.

+1
source

Well, therefore, first of all, let's understand what the structure of aggregation is. It queries only the available data and returns the result. He does NOT change the original documents! This is why the second part of the code you wrote performs aggregation, projection, and displays some result of the successful execution of the composite query.

To make the changes you are trying to make, you can try Martin Konecny's “quick and dirty” approach, or you can change the code to load the data and perform a new download.

Since I see that instead of using a decimal point, you use a comma in lat / long values, I would say that if you try to request this geospatial data later in time, you better load it again.

+1
source

MongoDB 3.2 seems to provide a fairly simple and elegant way to create GeoJSON points using an aggregation structure.

We had to convert about 2 million records twice a day, so the aggregation structure was the fastest and probably the most reliable approach.

The following is a Mongoose example on how to convert geolocation data from a collection with longitude / latitude to a collection with GeoJSON points.

 Locations .aggregate([ { $project : { _id: 0, "location": { "type": { $literal: "Point" }, "coordinates": ["$longitude", "$latitude"] } } }, { $out : 'test_1' }]) .exec(function(err,data) { if (err) { console.error(err); } else { console.log("Done transforming."); } }); 
0
source

Source: https://habr.com/ru/post/970100/


All Articles