I'm using the node-geoip module and performing an aggregation query. The schema against which I am performing the query looks like this:
var mongoose = require('mongoose');
require('./location.js');
module.exports = mongoose.model('Region',{
attr1: Number,
attr2: String,
attr3: String,
locations:[mongoose.model('Location').schema]
});
and
var mongoose = require('mongoose');
module.exports = mongoose.model('Location',{
attr1: Number,
latlong: { type: [Number], index: '2d' },
});
I need to perform a $geoNear operation in an aggregation query, but I'm running into a few problems. First, here is my aggregation method:
var region = require('../models/region');
var geo = geoip.lookup(req.ip);
region.aggregate([
{$unwind: "$locations"},
{$project: {
attr1 : 1,
attr2 : 1,
locations : 1,
lower : {"$cond" : [{$lt: [ '$locations.attr1', '$attr1']}, 1, 0]}
}},
{
$geoNear: {
near: { type:"Point", '$locations.latlong': geo.ll },
maxDistance: 40000,
distanceField: "dist.calculated"
}
},
{ $sort: { 'locations.attr1': -1 } },
{$match : {lower : 1}},
{ $limit: 1 }
], function(err,f){...});
The first problem I'm getting is that apparently geoNear must be in the first stage of the pipeline: exception: $geoNear is only allowed as the first pipeline stage
. So my question is, can I perform a geoNear search in the subdocuments without unwinding them? If so, how?
The other error message I get is errmsg: \"exception: 'near' field must be point\"
. What does this mean and what does it imply for my code? I have tried using near
as:
near: { type:"Point", '$locations.latlong': geo.ll },
First a disclaimer: I am not a Node/Mongoose expert so I am hoping you can translate the general formats to Node/Mongoose.
For the error:
errmsg: "exception: 'near' field must be point"
For a '2d' index this cannot be a GeoJson point and instead needs to be a "legacy coordinate pair". e.g.,
{
"$geoNear": {
"near": geo.ll,
"maxDistance": 40000,
"distanceField": "dist.calculated"
}
}
If you want to use GeoJSON you will need to use a '2dsphere' index.
With that change the $geoNear query will work with the array of points in the query. An example in the shell:
> db.test.createIndex({ "locations": "2d" })
> db.test.insert({ "locations": [ [1, 2], [10, 20] ] });
> db.test.insert({ "locations": [ [100, 100], [180, 180] ] });
> db.test.aggregate([{
"$geoNear": {
"near": [10, 10],
"maxDistance": 40000,
"distanceField": "dist.calculated",
num: 1
}
}]);
{
"result": [{
"_id": ObjectId("552aaf7478dd9c25a3472a2a"),
"locations": [
[
1,
2
],
[
10,
20
]
],
"dist": {
"calculated": 10
}
}],
"ok": 1
}
Note that you only get a single distance per document (the closest point) which is semantically not the same as doing the unwind and then determining the distance to every point. I cannot be sure if that is important for your use case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With