How to get unique mongodb? - 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
}
}
})

Related

Mongo $near - How to add a second query?

I have a route that does a $near search on my mongo database. It returns documents that have a geo tag within 100 miles. This request searches each document for "bandLocation". I have a second field, that is indexed, called bandTour - It holds several other geo locations in the same format. I want the request to also include these locations but have been unsuccessful - How do I add the second query?
Here is my route - If "bandLocation" is the only request, it works... How would I add "bandTour"?
router.get('/allbands/:lng/:lat', (req, res) => {
quoteGenerator.find(
{
"bandLocation.geometry":
{ $near :
{
$geometry: {
type: "Point",
coordinates: [parseFloat(req.params.lng), parseFloat(req.params.lat)]
},
$maxDistance: 160934,
}
},
"bandTour.geometry":
{ $near :
{
$geometry: {
type: "Point",
coordinates: [parseFloat(req.params.lng), parseFloat(req.params.lat)]
},
$maxDistance: 160934,
}
}
})
.then(
function(bands){
res.send(bands)
}
)
});
MongoDB only supports a single geo-expressions such as $near in a query. While aggregation does support geo queries, it is only supported as the first stage of the pipeline, so aggregation is not a solution in this case.
You would need to implement this as 2 queries, then combine the results. Since your sample query is requiring both locations to match, you could use a find with $near on bandLocation, projecting just the _id field. Then use the returned _id values to build a second query that tests for _id:{$in:[_array of ids_]} along with the $near on bandTour

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

MongoDB GeoNear Aggregation Result Size Limits

I'm using MongoDB 2.6.3 to query against a large collection of geospatial data. Specifically, I'm looking at querying the dataset for all pings within a few kilometers of a central location, and then collapsing them by user identifier to get a count of how many pings each user has.
Naturally, I'm using MongoDB aggregation for this, and specifically the $geoNear pipeline stage. However, it looks like, even though aggregation returns a cursor in 2.6.0, the $geoNear still has restrictions on the size of the result set tied to when aggregation returned a document. Namely, aggregation with $geoNear is returning only 65,000 records, while an equivalent (cursored) query is returning 200,000+.
Does anyone have any insight as to how I can perform large-scale aggregation then with geoNear?
edit:
Sample document:
{
"initial_epoch_time" : 1370062800,
"location" : [
-72.3458073902,
41.8241332683
],
"_id" : ObjectId("540a34050dc2520000912286"),
"__v" : 0
}
The following cursored query returns a count of ~200,000 documents, which I suspect is the correct number:
var cursor = db.pings.find( { location : { $near: { $geometry: { type: 'Point', coordinates: [-71.10560939999999, 42.3465666] }, $maxDistance: 10*1000 } } } )
var ctr = 0;
while(cursor.hasNext())
{ ctr++;
var ping = cursor.next()
}
print(ctr)
while the following aggregation-based query:
var cursor = db.pings.aggregate ( [ {$geoNear: { near: {type: "Point", coordinates: [-71.10560939999999, 42.3465666]},limit: 100000000, spherical: true, maxDistance: 10*1000, distanceField: "distance"} } ] )
var ctr = 0;
while(cursor.hasNext())
{ ctr++;
var ping = cursor.next()
}
print(ctr)
returns ~65,000 documents, regardless of maxDistance.
$geoNear as an command has a 16MB document limit to the output. I've found out that you won't retrieve any errors but the document will be automatically cut to the aggregation's document size limit. You can test by reducing size of your documents in the collection. You will get more results when you make your collection's documents smaller.
Line 235:
https://github.com/mongodb/mongo/blob/master/src/mongo/db/commands/geo_near_cmd.cpp

$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 geospatial query with time field?

I have a lot of different documents each containing a "savetime" field along with a point. Is it possible to query not only for all documents containing a location $near a point, but also within that same time (or within 1 second of each other)? What is the best way to perform the query to ensure maximal performance?
From the documentation:
A compound 2dsphere index can reference multiple location and non-location fields within a collection’s documents. You can arrange the fields in any order.
So in order for you to perform your queries that are constrained by a time, then you would create a compound index that has the "savetime" as it's first element. i.e:
db.collection.ensureIndex({ savetime: 1, loc: "2dsphere" })
That allows you to constrain dates normally while adding your additional constraints for finding near that point:
db.collection.find({
savetime: { $gte: new Date(<start>), $lte: new Date(<end>) },
loc: { $near :
{ $geometry :
{ type : "Point" ,
coordinates : [ <longitude> , <latitude> ] } ,
$maxDistance : <distance in meters>
}
}
}
})
For more information see the tutorials on creating and querying.