I would like to have a MongoDB collection and each document contains a geospatial polygon defined by latitude/longitude points (in GeoJSON). Then, I would like to take any given longitude/latitude point and check if it resides within any of the MongoDB polygons defined in the documents. Hypothetically, this is what the documents would look like.
{
"type" : "congressional",
"points" : [
{ "coords" : [
-141.0205,
70.0187 ]
},
...
{ "coords" : [
-141.0205,
70.0187 ]
}
]
}
Or maybe like so:
{ loc :
{ type : "Polygon" ,
coordinates : [ [ [ 0 , 0 ] , [ 3 , 6 ] , [ 6 , 1 ] , [ 0 , 0 ] ] ]
} }
And then I would query it, hypothetically, like so (most likely with Mongo's $geoWithin):
db.places.find( { loc : { $geoWithin : { $geometry : "EACH DOCUMENT IN COLLECTION"} } } )
Is geofencing, or something similar, possible to do with the current MongoDB feature-set? If so, how would it be done?
I believe you would have to first find every document from the collection., and then make a "$geoWithin" query for every document, passing in the Polygon to test against for each case.
Depending on the number of documents in your collection, that may or may not provide sufficient performance.
MongoDB has full support for geofencing or finding documents whose geometry intersects with a given geometry (point, polygon). The query below is an example. geometry of Collection is the field containing the geometry.
Document Example:
{ "geometry": {
"type": "Polygon",
"coordinates": [
[
[
-74.001487,
40.692346
],
[
-74.001755,
40.692057
],
[
-74.000977,
40.691951
],
[
-74.000827,
40.692297
],
[
-74.001487,
40.692346
]
]
]
}
}
JS Query:
//find quests bots that matches the users location
await Collection.find({ geometry:
{ $geoIntersects:
{
{
type: "Point",
coordinates: [
-73.99460599999999,
40.7347229
]
}
}
}
});
Related
I'm using MongoDB to store about 1 million documents representing regions.
Each document contains a coordinates record in the following format
"coordinates" : {
"longitude" : -77.02687,
"latitude" : 38.888565
}
Given a set of coordinates { x, y }, what query should I run to find the region ( document ) that is closest to it?
Based on the MongoDB geospatial-queries documentation the answer is quite simple.
In order to query for locations near a region you should follow these steps
Step 1
Create an index on the location field
db.places.createIndex( { location: "2dsphere" } )
Step 2
Find regions close to { -73.9667, 40.78 } ordered by closest locations
db.places.aggregate( [
{
$geoNear: {
near: { type: "Point", coordinates: [ -73.9667, 40.78 ] },
spherical: true,
query: { category: "Parks" },
distanceField: "calcDistance"
}
}
] )
So I have a query I am running at the moment which allows me to allow a business to show up if a person is within 10km.
However I want to add the ability to also show people if the user is inside a polygon.
I want to be able to do both queries at the same time in one query.
db.geom.insert({
"polygons": {
"type":"Polygon",
"coordinates": [[
[ 17.60083012593064, 78.18557739257812],
[ 17.16834652544664, 78.19381713867188],
[ 17.17490690610013, 78.739013671875],
[ 17.613919673106714, 78.73489379882812],
[ 17.60083012593064, 78.18557739257812]
]]
}
});
To do the polygon query I can do this.
db.geom.find({
polygons: {
$geoIntersects: {
$geometry: {
"type": "Point",
"coordinates": [17.3734, 78.4738]
}
}
}
});
I currently have a query that does this.
advertquery = { location:{ $geoWithin:{ $centerSphere: [ [ parseFloat(docs.location.coordinates[0]), parseFloat(docs.location.coordinates[1])], 10 / 6378.1] } } };
//START COUNT
var adquery = GEMS.countDocuments(advertquery).exec(function(err, count){
adcount = count
});
To get these two queries to work I have had to write this code.
advertquery = {
$or: [
{location:{
$geoIntersects: {
$geometry: {
"type": "Point",
"coordinates": [17.3734, 78.4738]
}
}
}
},
{ location:{
$geoWithin:{
$centerSphere: [ [ 17.3734, 78.4738], 10 / 6378.1] } } }
]
}
//START ADCOUNT
var adquery = GEMS.countDocuments(advertquery).exec(function(err, count){
if(err){console.log(err)}
console.error("TOTAL COUNTED : "+count);
adcount = count
});
However the countDocuments is not returning the count, just 0.
But when I run this is compass I get 1 result.
From the mongodb / mongoose documentation, it states countDocuments() does not support certain operators, that includes $geoWithin that you have used in the above query but can be replaced as mentioned in the docs.
I've been reading through mongo's docs on geospacial querying, and have things working well for singl Polygon types but am having trouble with MultiPolygon. What I want to do is essentially this:
Given a MultiPolygon outlining areas of exclusion:
{
"type" : "MultiPolygon",
"coordinates" : [
[
[
[
-117.873730659485,
33.6152089844919
],
[
-117.873065471649,
33.615048159758
],
[
-117.873044013977,
33.614690770386
],
[
-117.873666286469,
33.6146729008785
],
[
-117.873730659485,
33.6152089844919
]
]
]
]
}
I simply want to be able to pass in a Point to see if it is excluded. I've tried $geoIntersects just to see if it even can determine if a Point is included or not, but that doesn't work. In the end, I want to check that a point is not included within the exclusion list, but the query is simpler without the additional $not operator... Here's what I've been trying:
var geoPoint = {type: 'Point', coordinates: [-117.8731230, 33.6150696]};
db.myCollection.aggregate([
{$match: {'exclusionsPolygons': {$geoIntersects: {$geometry: geoPoint}}}}
]);
Note that if I do the same exact thing with a GeoJSON type of Polygon then it works just fine:
Given this single polygon:
{
"type" : "Polygon",
"coordinates" : [
[
[
-117.8711744,
33.6129677
],
[
-117.8751744,
33.6129677
],
[
-117.874444839148,
33.6162171973226
],
[
-117.87287399259,
33.6172714730352
],
[
-117.871410434393,
33.6165209730032
],
[
-117.8711744,
33.6129677
]
]
]
}
This query works just find and returns the item(s) whose singular polygon contains the point:
var geoPoint = {type: 'Point', coordinates: [-117.8731230, 33.6150696]};
db.myCollection.aggregate([
{$match: {'singularPolygon': {$geoIntersects: {$geometry: geoPoint}}}}
]);
After some tinkering, it turns out the result set was right and I was wrong...
I was using the areas of interest on the map to get addresses to try to query against. One such place was, I thought, in an exclusion polygon:
However, once I made the polygon larger the result set started coming back as I expected it to... So, I reset the polygon and double-checked the map content, finding that if I zoom in further the area of interest was actually excluded from the polygon as there are multiple areas of interest contained:
Whoops - my bad :)
I'm not able to optimize a distinct query using indexes.
My collection look like this :
{
"_id" : ObjectId("592ed92296232608d00358bd"),
"measurement" : ObjectId("592ed92196232608d0034c23"),
"loc" : {
"coordinates" : [
2.65939299848366,
50.4380671935187
],
"type" : "Point"
},
"elements" : [
ObjectId("592ed92196232608d0034c24"),
ObjectId("592ed92196232608d0034c26"),
ObjectId("592ed92196232608d0034c28")
]
}
I'm trying to execute a query like
db.mycol.distinct('elements', {
$and:[
measurement:{
$in:[
ObjectId("592ed92196232608d0034c23"),
ObjectId("592ed92196232608d0034c24")
]
},
{
loc:{
$geoWithin:{
$geometry:{
type:'Polygon',
coordinates:[[
[
2.0214843750000004,
50.25071752130677
],
[
2.0214843750000004,
50.65294336725709
],
[
3.0487060546875004,
50.65294336725709
],
[
3.0487060546875004,
50.25071752130677
],
[
2.0214843750000004,
50.25071752130677
]
]]
}
}
}
}
]
})
And I have this index :
{
measurement: 1,
loc: '2dsphere',
elements: 1
}
The query plan (db.mycol.explain().distinct(...)) shows an IXSCAN, but the query is taking ages. I added the index hoping that it could use a Mongo covered query. The doc states that
all the fields in the query are part of an index,
and all the fields returned in the results are in the same index.
So I guessed I needed an index including elements. But according to the query execution time, it's not using it.
What is the best way to index a collection for such a query ?
Covered queries don't work with arrays.
From the same page referred in the question:
Restrictions on Indexed Fields
An index cannot cover a query if:
any of the indexed fields in any of the documents in the collection includes an array. If an indexed field is an array, the index becomes a multi-key index and cannot support a covered query.
I have a dataset of ~400k objects in the format:
{
"trip": {
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[
-73.9615,
40.6823
],
[
-73.9704,
40.7849
]
]
},
"properties": {
......
}
}
}
I tried making a 2dsphere index on mLab like so:
{"trip.geometry" : "2dsphere"}
Which I assume just calls:
db.collection.createIndex( {"trip.geometry" : "2dsphere"} )
When I try to do a $geoWithin query like so (about 500 hits):
db.collection.find(
{
"trip.geometry": {
$geoWithin: {
$geometry: {
type : "Polygon" ,
coordinates: [
[
[-74.0345,40.7267],
[-73.9824,40.7174],
[-73.9934,40.7105],
[-74.0345,40.7267]
]
]
}
}
}}
)
I noticed it was very slow, ~2 seconds. I then tried deleting the index entirely, and the time increase was very slight. ~0.5 seconds. Is it possible that this query is not using the index the I had set? I've included the explain() here.
By my interpretation, the winning plan first fetches all the data based on a simple filter, then uses the 2dindex. Shouldn't it start out using the 2dindex, given that the lat and lon data aren't indexed directly?