Not getting results from $geoNear aggregate - mongodb

Can you help me figure out why this query isn't returning results?
I imported a shape file using ogr2ogr to convert it to geoJson, then imported it to Mongo using this command:
"mongoimport --db ht--collection facilities< f.json"
Then, I created index like this: "db.facilities.ensureIndex({"geometry":"2dsphere"})"
Here's a sample document, along with the query that isn't returning anything and the index:
db.epa_facilities.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [ -74.501340, 39.944520 ] },
distanceField: "dist.calculated",
maxDistance: 3,
query: { type: "public" },
includeLocs: "dist.location",
spherical: true,
distanceMultiplier: 3959
}
}
])
Here's the document (properties removed for brevity):
{
"_id" : ObjectId("54ff20a90e46de508d1dae93"),
"type" : "Feature",
"properties" : {
… },
"geometry" : {
"type" : "Point",
"coordinates" : [
-74.50134,
39.9445200009289
]
}
}
And here's the index. I tried with both "geometry" and with "geometry.coordinates" with the same result:
{
"geometry.coordinates" : "2dsphere"
}

When you execute geoNear, in addition to the location filter, the query filter is also applied. Your query filter is { type: "public" } if none of the documents that satisfy $geoNear are of type "public" then you will get no documents as a result.

Related

$near operator on a nested object list item

I have mongo db with a collection of objects with a nested object list (events) like this:
{
"_id" : ObjectId("59db84093f2fba2bf0bcfa90"),
"progressStatus" : "NOT_STARTED",
"events" : [
{
"issueDate" : ISODate("2017-10-09T00:00:00.000Z"),
"eventType" : "xyz",
"location" : {
"point" : {
"type" : "Point",
"coordinates" : [
25.6011977000001,
45.6579755
]
}
},
"cancelled" : false,
}
]
}
Trying to make a query using $near or $nearSphere operator on events.$.location:
{
"events":{
"$elemMatch":{
"eventType":"xyz",
"$and":[
{
"cancelled":false
},
{
"location.point":{
"$nearSphere":{
"$geometry":{
type:"Point",
coordinates:[
25.601198,
45.657976
]
},
"$maxDistance":20.4
}
}
}
]
}
}
}
This query gives me an error:
Error: error: {
"waitedMS" : NumberLong(0),
"ok" : 0,
"errmsg" : "geoNear must be top-level expr",
"code" : 2
}
How should it be done?
neptune, this happens because geospatial queries with $nearSphere uses geoNear command to fetch documents, and the geoNear expression (when the command is run) needs to be at the top level on query. In your example, it happens to be at low levels (within elemMatch), raising an error when constructing the call to geoNear.
As I understand, your 2dsphere index is on "events.location.point", right ?
So, you can make this query like:
db.sample6.find({"events": {$elemMatch: {$and: [{eventType: "xyz"},{cancelled: false}]}}, "events.location.point": {"$nearSphere": {"$geometry": {type: "Point", coordinates: [25.601198, 45.657976]}, "$maxDistance": 20.4}}})
or just
db.sample6.find({"events.eventType": "xyz", "events.cancelled": false, "events.location.point": {"$nearSphere": {"$geometry": {type: "Point", coordinates: [25.601198, 45.657976]}, "$maxDistance": 20.4}}})
This last one I think is more wise, since it has already AND behaviour, without the need of $and use. Also, if it's possible, it would be cleaner and less confusing (since these queries have a lot of brackets and parentheses) to construct the geospatial info right on "location" field (if it only contains the coordinates).

How to use $geoNear with embedded GeoJsonPoint field?

I have a collection for places with the following fields:
{
"name":"AAAAA",
.
.
"location" : {
"loc" : {
"type" : "Point",
"coordinates" : [
25.381911,
37.109551
]
}
.
.
}
}
I want to use aggregation with geoNear and I cannot find a way to set the field for the location. With a query like this:
db.places.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [ -73.99279 , 40.719296 ] },
distanceField: "dist",
maxDistance: 2,
query: {
"categories.categoryList":"Cocktail Bar"
},
includeLocs: "location.loc",
num: 5,
spherical: true
}
}]);
I get this error:
"errmsg" : "exception: geoNear command failed: { ok: 0.0, errmsg: \"no geo indices for geoNear\" }"
I think the problem is that the "loc" field is embedded in the location document and I cannot "tell" mongo to search near "location.loc".
The solution finally was to not include the GeoJsonPoint in the embedded location document. I just used "loc" in the same way as name and MongoDB "understood" that there were coordinates in the document.

geoNear exception: 'near' field must be point

I have run the following query successfully in the mongo shell:
db.runCommand({
geoNear : "stores",
near : { type : "Point", coordinates : [ -3.978, 50.777 ] },
spherical : true,
limit : 10
})
I am trying to convert this into a mongoose query for my node service as shown in the docs.
Store.geoNear(
{ type : "Point", coordinates : [-3.978, 50.777]},
{ spherical : true, limit : 10 },
function (error, results, stats) {
//do stuff with results here
});
This is returning the following error:
MongoError: exception: 'near' field must be point
My Store schema is defined like this:
var storeSchema = new Schema({
// irrelevant fields...
locations : [
{
address : {
streetAddress : String,
postalCode : String
}
coords : {
type : [Number],
index : '2dsphere'
}
}
]
})
There is only one 2dsphere index on the collection, and as I mentioned, it works through the shell, just not with mongoose.
Edit: Other things I've tried without success:
Falling back to using mongodb native driver (same error, so I suspect it's mongodb rather than mongoose causing the problem):
Store.collection.geoNear(
{ type : "Point", coordinates : [-3.978, 50.777]},
{ spherical : true, limit : 10 },
function (error, results, stats) {
//do stuff with results here
});
Falling back to using legacy coordinates instead of geopoints (both mongoose and native (same error)):
Store.geoNear(
-3.978, 50.777,
{ spherical : true, limit : 10 },
function (error, results, stats) {
//do stuff with results here
});
Using runCommand from mongoose (this errors differently, saying that Store.db.command is not a function - the correct way to call this from mongoose would be an acceptable answer):
Store.db.command({
geoNear : "stores",
near : { type : "Point", coordinates : [ -3.978, 50.777 ] },
spherical : true,
limit : 10
}, function(error, results){})
Finally managed to work out how to fall back to use runCommand via the mongodb native driver:
Store.db.db.command({
geoNear : "stores",
near : { type : "Point", coordinates : [ -3.978, 50.777 ] },
spherical : true,
limit : 10
}, function(error, results){})

MongoDB: Using $geoIntersects or $geoWithin with $near in one query

I would like to query for all documents that have a polygon that a point is contained in and then for that result set, order it based on closeness of that point to the location of the document.
So imagine I have a database of friends because I'm just that cool, and would like to see which friends are within the my range and would be willing to come play. (each friend has a play-date polygon which is the range they are willing to travel for a play-date)
For all matches I would like to them proceed to see which friend I should call to come based on his actual address and its distance to my point (which is my address) so that I can determine if I am ok with them coming from far away. (lets say 300 meters)
So far I have below a query to find polygons that my point is contained within but I do not know how to include the $near operator of mongodb
For JSON:
{
"_id" : "objid",
"FRIEND_NAME" : "Bobby",
"GEOMETRY" : {
"type":"Polygon",
"coordinates":[[
[-73.98779153823898,40.718233223261],
[-74.004946447098,40.723575517498],
[-74.006771211624,40.730592217474],
[-73.99010896682698,40.746712376146],
[-73.973135948181,40.73974615047701],
[-73.975120782852,40.736128627654],
[-73.973997695541,40.730787341083],
[-73.983317613602,40.716639396436],
[-73.98779153823898,40.718233223261]
]]},
"FRIEND_POSITON" : {"lon" : -73.992188, "lat" : 40.729359 }
}
This works:
db.friends.find({
"PLAYDATE_RANGE":{
"$geoIntersects":{
"$geometry":{
"type":"Point",
"coordinates":[-73.98652, 40.752044]
}
}
}
})
This does not:
db.friends.find([
{
"PLAYDATE_RANGE":{
"$geoIntersects":{
"$geometry":{
"type":"Point",
"coordinates":[-73.98652, 40.752044]
}
}
}
},
{
"FRIEND_POSITON":{
"$geoNear":{
"near":{
"type":"Point",
"coordinates": [-73.98652, 40.752044]
},
"maxDistance":300
}
}
}
])
Please help me with the query above that does not work.
This requires an aggregate pipeline. As per mogodb doc for $geoNear, You can only use $geoNear as the first stage of a pipeline. The aggregate function has an entry for an additional query which is where the polygon query will be used to narraw down results based on inclusion in the PLAYDATE_RANGE field of the document.
db.friends.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [-73.98652, 40.752044] },
maxDistance: 300,
distanceField: "friends.calculated_distance",
query: {
"PLAYDATE_RANGE": {
"$geoIntersects": {
"$geometry": {
"type": "Point",
"coordinates":[-73.98652, 40.752044]
}
}
}
},
spherical: true
}
}
])
P.S. note that only one geospatial index can be used so put it on the FRIEND_POSITION field. If adding a 2sphere index that requires a correctly formed GeoJSON value, specifically,
"FRIEND_POSITION" : { "type" : "Point", "coordinates" : [ -73.992188, 40.729359 ] }
So the document should look like:
{
"_id" : "objid",
"FRIEND_NAME" : "Bobby",
"GEOMETRY" : {
"type": "Polygon",
"coordinates":[[
[-73.98779153823898,40.718233223261],
[-74.004946447098,40.723575517498],
[-74.006771211624,40.730592217474],
[-73.99010896682698,40.746712376146,
[-73.973135948181,40.73974615047701],
[-73.975120782852,40.736128627654],
[-73.973997695541,40.730787341083],
[-73.983317613602,40.716639396436],
[-73.98779153823898,40.718233223261]
]]},
"FRIEND_POSITION" : {
"type" : "Point",
"coordinates" : [ -73.992188, 40.729359 ]
}
}

MongoDb $near and query

I have a collection of documents in structure as below
{ _id: ObjectId("54723e44ec73a702fc979fc9"),
Start: { type: "Point", coordinates: [ -0.15261409999993703, 51.4428311 ] },
End: { type: "Point", coordinates: [ -0.1258020000000215, 51.44695 ] }
}
I am running the following query to try and find documents where the start is 2000 units from a point and the end is 1 unit from a point.
"Start" :
{ "$near" :
{ "$geometry" :
{ "type" : "Point",
"coordinates" : [-0.12580200000002151, 51.44695]
}
},
"$maxDistance" : 2000.0
},
"End" :
{ "$near" :
{ "$geometry" :
{ "type" : "Point",
"coordinates" : [-0.12580200000002151, 51.44695]
}
},
"$maxDistance" : 1.0
}
When I run the query it always returns the documents as if it is doing an or. So where start is x units from a point OR end is x units from a point. So if I run it over the following two documents it returns both where I would only expect the first to be returned.
{ _id: ObjectId("54723e44ec73a702fc979fc9"),
Start: { type: "Point", coordinates: [ -0.15261409999993703, 51.4428311 ] },
End: { type: "Point", coordinates: [ -0.1258020000000215, 51.44695 ] }
}
{ _id: ObjectId("54724f0cec73a70c383a27d4"),
Start: { type: "Point", coordinates: [ -0.15261409999993703, 51.4428311 ] },
End: { type: "Point", coordinates: [ -0.09553900000003068, 51.427025 ] }
}
I am sure I should be able to do this as in
http://blog.mongodb.org/post/50984169045/new-geo-features-in-mongodb-2-4
"Additionally, we can have multiple 2dsphere indexes in the same compound index. This allows queries like: “Find routes with a start location within 50 miles from JFK, and an end location within 100 miles of YYC”."
For clarrification. The query shown above is supposed to be doing and AND query on START location $near point AND END location $near point. But what it actually appears to be doing is START location $near point OR END location $near point.
How do I do and AND query on two $near queries in a single document?