SwissFr
SwissFr

Reputation: 188

Error when using $mod with an array element

I have documents with GeoJSON points and I want to count them by "square" using the coordinates. In order to do this I subtract my latitude/longititude with the modulus of the same latitude/longitude and the dimension of the square.

I got an error :

"errmsg" : "$mod only supports numeric types, not Array and NumberDouble"

I don't understand because I use the dot notation to extract the latitude and the longitude. Why does it say it's an array ?

I had no problem using the same query but with coordinates stored into two different properties instead of inside the same array.

Example document :

{
"_id" : ObjectId("560dcd15491a065d6ab1085c"),
"nodeLoc" : 
    {
        "type" : "Point",
        "coordinates" : 
        [
                2.352221,
                48.856612
        ]
    }
}

Aggregation :

db.collection.aggregate(
        [ 
            {
                $group:
                {
                    _id:
                    {
                        latGroup: {$subtract: ["$nodeLoc.coordinates.1", {$mod: ["$nodeLoc.coordinates.1", 0.5]}]},
                        lonGroup: {$subtract: ["$nodeLoc.coordinates.0", {$mod: ["$nodeLoc.coordinates.0", 0.5]}]},
                    },
                    count: {$sum: 1}
                }
            }
        ]
    )

I expect a result like this :

latGroup : 2 lonGroup : 48,5 count : 1
...

Thanks in advance

Upvotes: 1

Views: 155

Answers (1)

Sede
Sede

Reputation: 61225

Starting from MongoDB 3.2, you can use the $arrayElemAt operator to return an element at a specific index.

db.collection.aggregate([ 
    { "$group": { 
        "_id": { 
            "latGroup": { 
                "$subtract": [ 
                    { "$arrayElemAt": [ "$nodeLoc.coordinates", 1 ] }, 
                    { "$mod": [
                        { "$arrayElemAt": [ "$nodeLoc.coordinates", 1 ] }, 
                        0.5  
                    ]} 
                ] 
            }, 
            "longGroup": { 
                "$subtract": [ 
                    { "$arrayElemAt": [ "$nodeLoc.coordinates", 0 ] }, 
                    { "$mod": [
                        { "$arrayElemAt": [ "$nodeLoc.coordinates", 0 ] },
                        0.5  
                    ]} 
                ] 
            }  
        }, 
        "count": { "$sum": 1 } 
    }}
])

From MongoDB version <= 3.0, you need to de-normalize the "coordinates" array then first $group by _id" and use the $first and $last accumulator which respectively return the first and last value in the "coordinates" array. From there, you can easily regroup your documents using the $mod operator.

db.collection.aggregate([
    { "$unwind": "$nodeLoc.coordinates" }, 
    { "$group": { 
        "_id": "$_id",  
        "latGroup": { "$first": "$nodeLoc.coordinates" }, 
        "longGroup": { "$last": "$nodeLoc.coordinates" } 
    }}, 
    { "$group": {
        "_id": { 
            "latgroup": { 
                "$subtract": [ 
                    "$latGroup", 
                    { "$mod": [ "$latGroup", 0.5 ] } 
                ] 
            }, 
           "lonGroup": { 
               "$subtract": [ 
                   "$longGroup", 
                   { "$mod": [ "$longGroup", 0.5 ] } 
               ] 
           }
        },
        "count": { "$sum": 1 }
    }}
])

Upvotes: 1

Related Questions