Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you access a specific array item in MongoDB projection aggregation?

I'm trying to create a projection within a MongoDB aggregation function, see the following:

[
    {$match : {"geo" : {$ne: null}}},
    {$project : {"id" : "$id_str", lat: "$geo.coordinates.0", lon: "$geo.coordinates.1"}}
]

However when I do this it does not pass over the array item it simply projects an empty array to the properties lat and lon.

What is needed here? I have looked at the Documentation but cannot figure it out, and even tried a permutation of $unwind and $group but with no success.

like image 989
Stephen Avatar asked Jun 23 '15 08:06

Stephen


People also ask

How do you get a specific object from an array in MongoDB?

To search the array of object in MongoDB, you can use $elemMatch operator. This operator allows us to search for more than one component from an array object.

How do I filter an array in MongoDB aggregation?

Filter MongoDB Array Element Using $Filter Operator This operator uses three variables: input – This represents the array that we want to extract. cond – This represents the set of conditions that must be met. as – This optional field contains a name for the variable that represent each element of the input array.

How do you find documents with a matching item in an embedded array?

Use $match With $eq to Find Matching Documents in an Array in MongoDB. Use $match With $all to Find Matching Documents in an Array in MongoDB.


2 Answers

The feature that will help you achieve this is not yet available. However, there will be a new aggregation operator that gives an array element for a given index. The new expression is called $arrayElemAt

Use the new aggregation operator that's available for MongoDB versions 3.2.X and greater, this returns an array element for a given index. The new expression is called $arrayElemAt. It takes two arguments, an array and an index and returns the element at the given index in the array. Negative indices are accepted as indexes from the back of the array. If the index is out of bounds, it returns the missing value, meaning the field will not exist in the output:

var pipeline = [    
    { $match : {"geo" : {$ne: null}}},
    {
        $project: {
            _id: "$id_str", 
            lat: { $arrayElemAt: ['$geo.coordinates', 0] },
            lon: { $arrayElemAt: ['$geo.coordinates', 1] }
        }
    }
];

As a workaround for now (assuming the coordinates array will always have two elements at any given time), you could try the following aggregation pipeline which will take advantage of the $first and $last group accumulator operators to get the elements after a $sort:

var pipeline = [
    {$match : {"geo" : {$ne: null}}},
    { "$unwind": "$geo.coordinates" },
    { "$sort": {"geo.coordinates": 1} } ,
    {
        "$group": {
            "_id": "$_id",
            "lat": { "$first": "$geo.coordinates" },
            "lon": { "$last": "$geo.coordinates" }
        }
    }
];
like image 80
chridam Avatar answered Jan 25 '23 22:01

chridam


you can simply use this in the project stage of the pipeline:-

{ $project:{ _id:'$_id', lat: {$arrayElemAt : ['$geo.coordinates',0]}, lon: {$arrayElemAt : ['$geo.coordinates',1]}, } }

if you want to know about the arrayElemAt aggregation operator in more detail then click on the below-given link:-

https://docs.mongodb.com/manual/reference/operator/aggregation/arrayElemAt/

for your more information:-

"All documents must store location data in the same order. If you use latitude and longitude as your coordinate system, always store longitude first. MongoDB’s 2d spherical index operators only recognize [ longitude, latitude] ordering."

like image 40
Amit Roy Avatar answered Jan 26 '23 00:01

Amit Roy