$geoIntersects don't work like expected - mongodb

I have a question to the $geoIntersects-Operator.
I have the following searchBox and collection-content:
> BOX
{
"type" : "Polygon",
"coordinates" : [
[
[
0,
0
],
[
3,
0
],
[
3,
3
],
[
0,
3
],
[
0,
0
]
]
]
}
> db.polygon.find()
{ "_id" : "Poly1", "shape" : { "type" : "Polygon", "coordinates" : [ [ [ 0, 0 ], [ 3, 0 ], [ 3, 3 ], [ 0, 3 ], [ 0, 0 ] ] ] } }
{ "_id" : "Poly2", "shape" : { "type" : "Polygon", "coordinates" : [ [ [ 3, 0 ], [ 6, 0 ], [ 6, 3 ], [ 3, 3 ], [ 3, 0 ] ] ] } }
> db.polygon.find( {shape: {$geoIntersects: {$geometry: BOX}}}, {_id:1})
{ "_id" : "Poly1" }
Like you can see, the BOX and Poly1 are identical.
Poly2 shared an edge with BOX.
So when I was executing the $geoIntersects-Query I was expecting that both polygon’s where returned because of the shared edge, but only Poly1 was found.
Can somebody explain that to me? Or did I made a stupid mistake I don’t see :(
Auf Wiedersehen, Andre

Good question. It looks like it's a bug or the documentation is not accurate. Just want to share the results of my small research on the issue
Point:
.find( {shape: {$geoIntersects: {$geometry: {type: "Point", coordinates : [3,0] }}}}, {_id:1})
No surprise it returns both Poly1 and Poly2.
LineString:
.find( {shape: {$geoIntersects: {$geometry: {type: "LineString", coordinates : [[3,0], [3, 3]] }}}}, {_id:1})
Returns Poly1 only, what if we revert the order of line points?
.find( {shape: {$geoIntersects: {$geometry: {type: "LineString", coordinates : [[3,3], [3, 0]] }}}}, {_id:1})
Returns Poly2 only now. So the order of the points is important for LineString which is really weird to me.
Polygon:
Let's also try to change the order of points for polygon query.
.find( {shape: {$geoIntersects: {$geometry: {type: "Polygon", coordinates : [ [ [ 3, 0 ], [ 3, 3 ], [ 6, 3 ], [ 6, 0 ], [ 3, 0 ] ] ]}}
Now even the order of points for line [ 3, 0 ], [ 3, 3 ] matches Poly1 definition but it still returns Poly2 only.
Summary:
So when the documentation says that
This includes documents that have a shared edge
It's no surprise true for Point, it is partially true for LineString because the order of points is important! Finnaly it's not true at all for Polygon.
This is sad in fact but really good to know. I wish I were doing something wrong during my research and would be glad if someone drop in with a good explanation.

just use smaller numbers. for triangles like these:
[{
_id:54cfbc19d9e1f418373ee427,
geo:{type:Polygon,
coordinates:[[[0.3,0.3],[0,0.3],[0,0],[0.3,0.3]]]}
},
{_id:54cfbc19d9e1f418373ee428,
geo:{type:Polygon,
coordinates:[[[0,0],[0.3,0],[0.3,0.3],[0,0]]]}
}]
.find({
geo: {
$geoIntersects: {
$geometry: {
type: "Point" ,
coordinates: [0.005,0.005]
}
}
}
})
will give you right result.
I guess that $geoIntersects count that Earth is sphere.

Related

$geoIntersects returns no results

I am querying a polygon, to check if a point is inside of it or not, but no results are returned. I am in the mongo shell: (MongoDB shell version: 3.2.6)
db.restPolygons.find();
{
"_id" : ObjectId("586e663175c32828be59e3a9"),
"zoneCoordinates" : {
"type" : "Polygon",
"coordinates" : [
[ 2, 0 ],
[ 6, 0 ],
[ 6, 2 ],
[ 2, 2 ],
[ 2, 0 ]
]
}
}
db.restPolygons.find({
"zoneCoordinates": {
"$geoIntersects": {
"$geometry": {
"type": "Point",
"coordinates": [3 ,1]
}
}
}
}).count();
0
Your polygon is invalid, it's missing a level of enclosing array in the coordinates field. This one should work:
> db.geo.find()
{
"_id": ObjectId("586e663175c32828be59e3a9"),
"zoneCoordinates": {
"type": "Polygon",
"coordinates": [
[
[2, 0],
[6, 0],
[6, 2],
[2, 2],
[2, 0]
]
]
}
}
> db.geo.find({
"zoneCoordinates": {
"$geoIntersects": {
"$geometry": {
"type": "Point",
"coordinates": [3 ,1]
}
}
}
}).count()
1
You can check the validity of your GeoJSON object in GeoJSONLint

Unrecognized operator: $geoIntersects

I am running this query and I am getting :
"Uncaught Error: Unrecognized operator: $geoIntersects"
RestPolygons.findOne({restRefId: 'Fsmbi94HahsRJH9rT', zoneCoordinates: {$geoIntersects:
{$geometry:{ "type" : "Point",
"coordinates" : [34.7791114, 32.077278299999996]}
}
}})
If I replace $geoIntersects with $geoWithin, i get "Unrecognized operator: $geoWithin"
https://docs.mongodb.com/manual/reference/operator/query/geoIntersects/
RestPolygons.find(
{
loc: {
$geoIntersects: {
$geometry: {
type: "Polygon" ,
coordinates: [
[ [ 0, 0 ], [ 3, 6 ], [ 6, 1 ], [ 0, 0 ] ] // for use like
]
}
}
}
}
)
It has been added in version 2.4 geoIntersects
Which version of mongo are you running?

MongoDB find polygon coordinates using single point and radius

I have a collection with many polygon coordinates, which represent the different areas.
What my objective is I will send a lat, long and radius in a mongodb query which should return the polygon coordinates that falls within circle area.
Polygon coordinates:
{
"_id" : "300",
"name" : "MeKesler",
"centroid" : [
0,
0
],
"type" : "cnbd_id",
"coords" : [
[
39.8620784017,
-86.14614844330004
],
[
39.8625395793,
-86.15442037579999
],
[
39.8593030353,
-86.156373024
],
[
39.8586935926,
-86.15669488909998
],
[
39.8534225112,
-86.15854024890001
],
[
39.850391456,
-86.1589050293
],
[
39.8511657057,
-86.1479830742
],
[
39.8511986523,
-86.14598751070002
],
[
39.856881704,
-86.14605188370001
],
[
39.8575241063,
-86.14605188370001
],
[
39.8620784017,
-86.14614844330004
]
]
}
My query:
db.collection.find({
"coords" : {
"$within" : {
"$center" : [
[ 39.863110, -86.168456],
2/69.1
]
}
}
})
Can anyone help on this?
I believe the problem is that your document is not valid geojson. The valid syntax for your polygon would be
{
"_id": "300",
"name": "MeKesler",
"centroid": {
type: "Point",
coordinates: [0, 0]
},
"type": "cnbd_id",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[39.8620784017, -86.14614844330004],
[39.8625395793, -86.15442037579999],
[39.8593030353, -86.156373024],
[39.8586935926, -86.15669488909998],
[39.8534225112, -86.15854024890001],
[39.850391456, -86.1589050293],
[39.8511657057, -86.1479830742],
[39.8511986523, -86.14598751070002],
[39.856881704, -86.14605188370001],
[39.8575241063, -86.14605188370001],
[39.8620784017, -86.14614844330004]
]
]
}
}
Also, you should consider creating a 2dsphere index on the geometry field.
Lastly, the geo query should use the $geoWithin operator, and run against the polygon, not against its coordinates.
db.collection.find({
"geometry" : {
"$geoWithin" : {
"$center" : [
[ 39.863110, -86.168456],
2/69.1
]
}
}
})

mongodb slow query performance

I have the following mongo test cluster in place
No of shards -2
No of config server -1
mongos instances -2
Replication not enabled
I have around 41 million records split across the shards, I have defined a compound index {field1:1,field2:1,field3:1}, my queries are of the form (field=1 and field2 between x and y), I expected the compound index to be useful for these queries, however the query response time is around 8 sec for the query I described. I am specifying only the fields of interest when I execute find.
Mongos is installed on the machine from where I execute the query and I am using java to do the querying.
Can someone throw some light on the possible reasons, why this query takes such a long time? I would be happy to provide more information if required.
The following is the output of explain command
{
"indexBounds": {
"LOGIN_ID": [
[
{
"$minElement": 1
},
{
"$maxElement": 1
}
]
],
"LOGIN_TIME": [
[
1262332800000,
1293782400000
]
]
},
"nYields": 7,
"millisShardTotal": 7410,
"millisShardAvg": 7410,
"numQueries": 1,
"nChunkSkips": 0,
"shards": {
"server1:27017": [
{
"nYields": 7,
"nscannedAllPlans": 1769804,
"allPlans": [
{
"cursor": "BtreeCursor LOGIN_TIME_1_LOGIN_ID_1",
"indexBounds": {
"LOGIN_ID": [
[
{
"$minElement": 1
},
{
"$maxElement": 1
}
]
],
"LOGIN_TIME": [
[
1262332800000,
1293782400000
]
]
},
"nscannedObjects": 1763903,
"nscanned": 1763903,
"n": 14081
},
{
"cursor": "BasicCursor",
"indexBounds": {},
"nscannedObjects": 5901,
"nscanned": 5901,
"n": 0
}
],
"millis": 7410,
"nChunkSkips": 0,
"server": "server2:27017",
"n": 14081,
"cursor": "BtreeCursor LOGIN_TIME_1_LOGIN_ID_1",
"oldPlan": {
"cursor": "BtreeCursor LOGIN_TIME_1_LOGIN_ID_1",
"indexBounds": {
"LOGIN_ID": [
[
{
"$minElement": 1
},
{
"$maxElement": 1
}
]
],
"LOGIN_TIME": [
[
1262332800000,
1293782400000
]
]
}
},
"scanAndOrder": false,
"indexBounds": {
"LOGIN_ID": [
[
{
"$minElement": 1
},
{
"$maxElement": 1
}
]
],
"LOGIN_TIME": [
[
1262332800000,
1293782400000
]
]
},
"nscannedObjectsAllPlans": 1769804,
"isMultiKey": false,
"indexOnly": false,
"nscanned": 1763903,
"nscannedObjects": 1763903
}
]
},
"n": 14081,
"cursor": "BtreeCursor LOGIN_TIME_1_LOGIN_ID_1",
"oldPlan": {
"cursor": "BtreeCursor LOGIN_TIME_1_LOGIN_ID_1",
"indexBounds": {
"LOGIN_ID": [
[
{
"$minElement": 1
},
{
"$maxElement": 1
}
]
],
"LOGIN_TIME": [
[
1262332800000,
1293782400000
]
]
}
},
"numShards": 1,
"clusteredType": "ParallelSort",
"nscannedAllPlans": 1769804,
"nscannedObjectsAllPlans": 1769804,
"millis": 7438,
"nscanned": 1763903,
"nscannedObjects": 1763903
}
A sample document in my db is as follows
{
"_id" : ObjectId("52d5192c1a45f84e48c24e2f"),
"LOGIN_ID" : <loginId>,
"LOGIN_TIME" : NumberLong("1372343932000"),
"BUSINESS_ID" : <businessId>,
"USER_ID" : <userid>,
"EMAIL" : "a#b.com",
"SITE_POD_NAME" : "x",
"USER_AGENT" : "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML. like Gecko) Chrome/26.0.1410.43 Safari/537.31"
}
There are some other fields in the above doc which I cannot expose outside, but its a simple key value of string and string
This is how I query the db
DBObject dbObject = new BasicDBObject("BUSINESS_ID", businessId)
.append("LOGIN_TIME",
new BasicDBObject("$gte",start).append("$lt", end))
.append("LOGIN_TYPE", loginType);
long startTime = System.currentTimeMillis();
DBObject keys = new BasicDBObject("LOGIN_TIME", 1);
DBCursor find = collection.find(dbObject, keys);
int count = 0;
while (find.hasNext()) {
find.next();
count++;
}
long endTime = System.currentTimeMillis();
Mongo DB version is 2.4.9. Appreciate any help.
I see a following spots which could head into finding more about exact issue:
What is login_time and what does the numbers in the query range actually mean? The range looks quite wide by numeric difference. May be you filter criteria is vey wide-ranged? This is also indicative from the "nscanned" from the explain plan.
I see the index is on login_time and login_id, where as your query is on login_time and login_type. Just high-lighting that although you are using index, your query criteria is wide enough to cover a much larger index range and since the second criteria of login_type is not part of the index, query would need to fetch all "nscanned" documents to determine if it a valid record for this query.

MongoDB: How to use property in find query?

I have user collection:
{
"_id": { "$oid" : "514C438232F5699004000014" },
"gender": 1,
"loc": {
"coordinates": [
0.777084,
0.701690
],
"type": "Point"
},
"name": "H1",
"radius": 1
},
{
"_id": { "$oid" : "514C438232F5699004000014" },
"gender": 1,
"loc": {
"coordinates": [
0.677084,
0.701690
],
"type": "Point"
},
"name": "H2",
"radius": 0.4
}
db.user.ensureIndex( { loc : "2dsphere" } )
I need to write query and use radius property from collection's row ( "radius": 1 ) in find query like this:
db.user.find( { loc: { $geoWithin :{ $centerSphere : [ [0.7, 0.7 ] , radius ]} } } )
But mongo returns:
JavaScript execution failed: ReferenceError: radius is not defined
I have tried db.user.find( { loc: { $geoWithin :{ $centerSphere : [ [0.7, 0.7 ] , this.radius ]} } } )
I think you have to do a two way query. First fetch the radius of a given user, then search for all location within this radius.