What is the difference between "queries" and "commands" in MongoDb - mongodb

Hello MongoDB documentation specifies that there are several ways to retrieve documents near a geographical position :
using "queries" (in find queries for instance) :
https://docs.mongodb.com/v3.0/reference/operator/query-geospatial/
or using "commands" :
https://docs.mongodb.com/manual/reference/command/nav-geospatial/
I don't understand the difference between commands and operator/queries ? These commands seem to do exactly the same thing as their query counterparts ?
PS : I use scala reactivemongo connector in my application.

I remembered reading it from mongodb definitive guide 2nd edition (mongo 2.6), however this book only covers mongo2.6.
query command cover several tasks like CRUD, drop database. While database Command cover everything else, including administrative tasks, cloning database, etc. (this book uses mongodb v2.6, I am sure in mongodbV3.2 queryCommand has more functions that can cover some adminitrative tasks)
query in mongoshell returned a cursor, while database command returned an document that always has "ok" status, and one or more information.
example querying geolocation with database Command
db.runCommand( {
geoNear: <collection> ,
near: { type: "Point" , coordinates: [ <coordinates> ] } ,
spherical: true,
...
} )
example of querying database with query command
db.places.find(
{
location:
{ $near :
{
$geometry: { type: "Point", coordinates: [ -73.9667, 40.78 ] },
$minDistance: 1000,
$maxDistance: 5000
}
}
}
)

Related

MongoDB $near query accuracy issue

In my application I would like to query items that are close by (e.g. within 5km) to a coordinate and I tried to use $near to achieve that. With a quick look I thought it worked but after I tested it further it seems the query is somewhat inaccurate. Here is my setup:
I selected 2 coordinates that are a bit less than 5km apart from each other:
61.4644750214197, 23.8426943813556
61.497133399999996, 23.778528100000003
(At least according to tools like this, this or this the distance between those coordinates should be about ~4,99km)
I added one of the coordinates into empty "items" collection:
db.items.insert({
"geo" : {
"type" : "Point",
"coordinates" : [
61.4644750214197,
23.8426943813556
]
}
});
I added "2dsphere" index to the collection make geospatial queries possible:
db.items.createIndex( { geo : "2dsphere" } )
Finally, I used the other coordinate with $near query:
db.items.find({geo: {
$near: {
$geometry: {
type: "Point" ,
coordinates: [ 61.497133399999996, 23.778528100000003 ]
},
$maxDistance: 5000 // according to docs with '2dsphere' index and GeoJSON this is is meters
}
}}).count()
I expected the result to be 1 but instead it is 0. Even if I set $maxDistance to 7000 the result is still 0, but if I set it to 8000 the result will be 1.
Am I doing something wrong or are MongoDB geospatial queries (or just $near query?) that inaccurate? If so, is there a better way to get accurate results for this kind of query? This is my first time dealing with geospatial queries in MongoDB so there is probably a trivial explanation for my problem.
EDIT:
Basically I was dreaming of a functionality to show all items in map within X kilometres from users current location and X could be determined by user. It would be awkward if an item within 5km would not be visible even when the user wants to filter items within 7km.
I have tried most of the options for doing this query, like $centerSphere, $nearSphere and geoNear with similar results. They all seem to claim that the distance between my earlier mentioned coordinates is somewhere between 7-8km. I'm starting to think either 1. I'm missing some key peace of information about how distances work in general or 2. it simply is not possible to solve my problem with mongodb. Below are my queries for the other options:
$centerSphere (0 results with 5, 6 and 7km but 1 result with 8km):
db.items.find( { geo: {
$geoWithin: { $centerSphere: [ [ 61.497133399999996, 23.778528100000003 ], 5/6378.1 ]
}
}}).count()
geoNear (0 results with maxDistance 5000, 6000 and 7000 but 1 result with 8000):
db.runCommand(
{
geoNear: "items",
near: { type: "Point", coordinates: [ 61.497133399999996, 23.778528100000003 ] },
spherical: true,
maxDistance: 5000
}
)
I understand I am late to the party, but for all those who are facing similar issue
The problem here is that when you store that data into "coordinates", it must be in the [longitude, latitude] order because this is how mongodb works. https://docs.mongodb.com/manual/geospatial-queries/#spherical I just ran your example with reversed order of coordinates and it worked as expected.
db.items.insert({
"geo" : {
"type" : "Point",
"coordinates" : [
23.8426943813556,
61.4644750214197
]
}
});
And then i ran
db.items.find({geo: {
$near: {
$geometry: {
type: "Point" ,
coordinates: [ 23.778528100000003 , 61.497133399999996]
},
$maxDistance: 5000
}
}}).count()
The count here is 1:
Hope it helps

How can I query a MongoDB collection by both a geo spatial index and a text index quickly?

Given the collection locations consisting of ~20,000,000 documents with 3 properties:
{
_id,
name, // string
geo // coordinate pair, e.g. [-90.123456, 30.123456]
}
and an index of name: 1 and a geo index setup like so:
{
"geo" : "2dsphere"
},
{
"v" : 1,
"name" : "geo_2dsphere",
"ns" : "db.locations",
"min" : "-180.0",
"max" : "180.0",
"w" : 1.0,
"2dsphereIndexVersion" : 2
}
How can I performantly query against this collection both on the geo_2dsphere index and on the name index?
When I run a $box query on the geo index only, it takes over 20 seconds to return 50 results. When I include a search against the name property it goes up even further.
If I run a $near query, then things can perform very quickly, but sometimes queries seem to (very randomly) go from ~200ms to many seconds. See this example where the only difference is one additional character on the name index which actually increases the time:
200ms:
{name: /^mac/, geo: {$near: {$geometry: {type: "Point", coordinates: [ -90.123456, 30.123456 ]}, $maxDistance: 20000}}}
18,000ms:
{name: /^macy/, geo: {$near: {$geometry: {type: "Point", coordinates: [ -90.123456, 30.123456 ]}, $maxDistance: 20000}}}
I can't understand why being more specific with an index is slowing things down so much. When I get more specific with a phrase, I have to drastically reduce the $maxDistance to something like 7,000 meters before the query returns in any reasonable amount of time.
Is there a better setup I should be doing here?
As has been pointed out to me by Blakes Seven, you cannot search across multiple indexes in MongoDB:
There is a "highlander rule" (there can be only one) in the query
evaluation that denies the usage of more than "one" "special" index in
a query evaluation. So you cannot have multiple "text" or muliple
"geospatial" or any combination of "text" and "geospatial" or usage of
any of those within an $or condition, that results in multiple index
selection.
So, I've opted to move over to Elasticsearch for this specific query, indexing only what I need to complete these multi-index queries, and then use those results to load the necessary Mongo documents. Works quickly, works well.

How to get unique mongodb?

If I have documents like this:
{firstname:"Jordan", lastname:"Snyder", age:6, homelocation:[<longitude, latitude>]}
In the mongo shell, how do I all the "distinct" firstname's across matching documents of people who live near a specific point (say 1 mile)? I see mongo has a distinct db.collection.distinct(field, query), but all the samples I see for finding anything "near" or "geowithin" (using homelocation field in my case) is using db.collection.find. I don't want all documents, I just want the distinct list of firstnames.
The query parameter of distinct uses the same format as the query selector parameter of find. So assuming a 2dsphere index on homelocation you can do something like:
db.test.distinct('firstname', {
homelocation: {
$near: {
$geometry: { type: "Point", coordinates: [ -73.9667, 40.78 ] },
$maxDistance: 1600 // In meters
}
}
})

$maxdistance no longer works when upgrading to MongoDB 2.6.3

I currently have a query on MongoDB which queries for devices located within a certain distance of a location. It's been working perfectly fine for months now. When I upgraded from MongoDB 2.4.10 to 2.6.3, the query no longer works and it returns no results.
{
"lastLocation": {
"$near": {
"$geometry": {
"type": "Point",
"coordinates": [ -122.195 , 37.423]
}
},
"$maxDistance": 10000
}
}
After playing around with it, it seems that without $maxDistance, the query works. However, I can't get $maxDistance to work at all.
I have two databases side by side with the exact same data, one with each version of MongoDB, 2.4 returns data, 2.6 does not (so it's not because there aren't devices within that distance).
Is there a known issue with maxDistance, or was there a change in units or how it works?
Index is as follows:
{
v: 1,
name: "lastLocation_2dsphere",
key: {
lastLocation: "2dsphere"
},
ns: "s-dev.devices",
background: true,
safe: true
}
Sample entry:
"lastLocation": [-122.19888, 37.42316]
Yes there have been a few changes in 2.6, kind of hidden in the documentation. In your case, in version 2.6 the $maxDistance needs to be inside of the $near document, not outside:
$maxDistance ChangesĀ¶
Description
For $near queries on GeoJSON data, if the queries specify a $maxDistance, $maxDistance must be inside of the $near document. In
previous version, $maxDistance could be either inside or outside the
$near document.
$maxDistance must be a positive value.
Solution
Update any existing $near queries on GeoJSON data that currently have the $maxDistance outside the $near document
Update any existing queries where $maxDistance is a negative value.
http://docs.mongodb.org/manual/release-notes/2.6-compatibility/
So in your case the query needs to look like this:
{
"lastLocation": {
"$near": {
"$geometry": {
"type": "Point",
"coordinates": [ -122.195 , 37.423]
},
"$maxDistance": 10000
}
}
}

MongoDB 'unable to find index for $geoNear query'

I'm just trying to get a simple near query working. Here's a sample of my document.
{"point":
{"type": "Point",
"coordinates": [30.443902444762696, -84.27326978424058]},
"created_on": {"$date": 1398016710168},
"radius": 180,
"user": {"$oid": "53543188eebc5c0cc416b77c"},
"_id": {"$oid": "53544306eebc5c0ecac6cfba"},
"expires_on": {"$date": 1399831110168}
}
and with mongod I tried the command:
db.bar.find({point: {$near: [-84.26060492426588, 30.45023887165371]}});
but I get this error:
error: {
"$err" : "Unable to execute query: error processing query: ns=foo.bar skip=0\nTree: GEONEAR field=point maxdist=1.79769e+308 isNearSphere=0 || First: notFirst: full path: point\nSort: {}\nProj: {}\n planner returned error: unable to find index for $geoNear query",
"code" : 17007
}
Maybe my google fu is not so sharp today but I couldn't find anything. Also, I ran the ensure index command. My intention is that these are map locations.
db.bar.ensureIndex({a:1});
db.bar.ensureIndex({geo:"2d"});
Few problems, you created your indexes on the foo collection of the foo database, but are querying the bar collection. You need to be on the correct collection.
Reading the document you have inserted you need to add a "2dsphere" index to support the geoJson objects. This index needs to be on the "point" element of your documents, so try
db.bar.createIndex({point:"2dsphere"});
You can then query as follows by providing a geoJson obj for the query:
db.bar.find(
{ point :
{ $near :
{
$geometry : {
type : "Point" ,
coordinates : [-84.27326978424058, 30.443902444762696] },
$maxDistance : 1
}
}
}
)
db.prod.createIndex({ "location": "2d" })
This solved for the same issue for me.
Where prod is my collection name and location is name of column which stores geo location (GeoPoint)
Some discussion about the same can be found here
So there seems to be a couple of things wrong here:
From the data you are showing and also your query information the relevant information is contained under the field point and in GeoJSON format. Your index creation:
db.foo.createIndex({geo: "2d"})
Does not "fail" because there presently isn't a field called "geo" and the field with the data should have been in that place. If you had used "point" instead, which is the correct field, then you would have received an error telling you that this type of index is invalid for the GeoJSON data. You need a "2dsphere" index:
db.points.createIndex({ "point": "2dsphere" })
Extending the same problem, again the data is in GeoJSON format and the form of the query is that for a legacy coordinate pair. You need to change the query arguments so that no longer fails:
db.points.find({point: {
$near: {
$geometry:{
type: "Point",
coordinates: [-84.26060492426588, 30.45023887165371]
}
}
}})
See the documentation for $near
In addition to the answers above, if you've already tried to create an Index and got some syntax or field wrong, you can run
db.<yourcollection>.dropIndexes();
To clean up all indexes and re-create them properly.
Also, the index should be created on the parent of "coordinates", not on coordinates itself:
{
"_id": 59ac03d168eaaa14c2a57a00",
"location":{
"type":"Point",
"coordinates":[
131.6667,
57.8368
]
},
"age":53,
"username":"Brandi_Greenfelder"
}
db.<yourcollection>.createIndex({ location: '2dsphere' });
Attention, there is "2d" and "2dsphere", use the second as it's the new thing.
If you're using mongoose to connect, this would be right answer:
db.collections.<yourcollection>.createIndex({ location : "2dsphere" })
Notice there is a "collections" property before collection itself. If it's not working, check db object in console.log:
console.log(db)