I'm having a series of points which forms a poly-line (path). I need to store it in the mongodb and query it nearby point.
How to store a poly-line in the mongodb?
Can i query it with a $near?
After saving the poly-line to mongodb, i will have a point and distance from the point and need to query the db.
EDIT :
i'm gone track the user's location using the GPS and i need to save the path in mongodb, how to do this?
Then the user can able to search path nearby his place with certain distance so i need to search the mongodb with the $near function.
So what you want is actually a LineString GeoJSON type, which is supported by MongoDB:
{
"loc": {
"type": "LineString",
"coordinates": [ [ 40, 5 ], [ 41, 6 ] ]
}
}
This allows you record a set of "coordinates" along a "path" that you wish to contain as a singular object in your data store. The main beauty of this is that you can do geospatial queries against such an object ( rather than a distinct "Point" and retrieve the whole "set" of connecting "Points" in a single document as "nearest". Better yet "multiple shapes" like this can be matched with ease.
So then you can just query with $near or other operators as appropriate:
db.collection.find({
"loc": {
"$near": {
"$geometry": {
"type": "Point",
"coordinates": [ 41,5 ]
},
"$maxDistance": 10000
}
}
})
A $near operator in a query will return the results ordered by the "nearest" to the queried GeoJSON object or legacy coordinate point provided to the query.
That should basically work for you.
Related
I am creating a matching system based on user proximity. The basic idea is I have user A at point A and user B at another point B. Both users have search filters that determine how far a user can be to make a match. This distance is in Kilometers.
Anyways would it be possible to do this in a single vanilla query (without using an aggregate query)? Here is the query I have so far
var loc = userA.location;
var rad = userA.radius;
{$near : {
$geometry : {
type : "Point",
coordinates : loc
},
$maxDistance : rad
}
}
How do I account for user's B preference though?
I was planning to store a geometry that was basically their circle of preference and then see if userA was within that circle, but this just doesn't seem right.
You already have the radius property stored on each user, so that is a good thing, and not only for a $maxDistance option, but also as a check to see if the distance between users is "less than" the radius attribute.
What you now basically need is a way to "see" that distance and "compare". For this you use the aggregation framework and $geoNear:
db.users.aggregate([
{ "$geoNear": {
"near": {
"type": "Point",
"coordinates": userA.location
},
"spherical": true,
"maxDistance": userA.radius,
"distanceField": "distance"
}},
{ "$redact": {
"$cond": {
"if": { "$lt": [ "$distance", "$radius" ] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
So what this does it executes the same sort of $near result along with the "maxDistance" constraint, but actually returns an additional property in the named "distanceField" representing the actual distance between found 'users'. The "spherical" option is required when the index is "2dsphere".
As an aggregation "pipeline", this allows another operation to act on the output. The $redact stage makes a "logical comparison" of the existing "radius" data and the generated "distance" field, to see if that distance is "less than" the stored radius data.
Only when that condition is true is the document returned via $$KEEP, otherwise the distance is larger than the users radius as the document is removed from results via $$PRUNE.
That's how you make a comparison that respects the radius on the user data for returning results.
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
}
}
})
Let's say user finds documents with in Wellington New Zealand and provide coordinates of Wellington city: lat: -41.2864603, lng: 174.77623600000004.
But if there are no documents within this city I need to search documents within nearest cities within New Zealand country.
How could I find documents within country?
Most of the "heavy lifting" if this is really done by the general geospatial query itself, so long as you are using operations like $near or ideally $nearSphere with a 2dsphere index to allow for the curvature of the earth. Such queries basically find the "nearest" points to the queried "point" or GeoJSON object supplied and sort the results in the response that way.
Original implementations with the geoNear command had a default "limit" of 100 documents in the response and the ability to set the limit of documents in response. This is still generally valid as you would usually not want too many responses from such a query as there is a point where things are not "near" at all.
But the general case is that if you want to have additional query parameters in your logic then you can just add them to the existing query:
db.collection.find({
"$nearSphere": {
"$geometry": {
"type": "Point",
"coordinates": [ 174.77623600000004, -41.2864603 ]
}
},
"$or": [
{ "city": "Wellington" },
{ "country": "New Zealand" }
]
})
The logic there is that the queried objects must be "near" the queried location data and also either have data matching the "city" of "Wellington" $or matching "country" of "New Zealand".
You could alternately represent a complete "or" condition where the object did not necessarily match the geolocation condition, as long as the other query parameters matched something:
db.collection.find({
"$or": [
{ "$nearSphere": {
"$geometry": {
"type": "Point",
"coordinates": [ 174.77623600000004, -41.2864603 ]
}
}},
{ "city": "Wellington" },
{ "country": "New Zealand" }
]
})
That is of course if you "really want to" as it should not be needed generally speaking as the selected objects will already be returned ordered by the "nearest" results and there are other ways to "bound" those results to within a certain "distance". But if you really want to specify additional "bounds" then you can.
Of course when issuing either a $near or $nearSphere query or other variation, a "2d" or "2dSphere" index must be in place. The other constraint is that the data must either be represented in your document in either the form of legacy coordinate pairs or in GeoJSON format. In all cases the representation is <longitude>, <latitude>.
So just having fields present in the document to represent "longitude" and "latitude" is not enough in itself and you need a supported storage format along with the "index" to use the operators as shown.
The other data in the conditions can be contained in other indexes, following the guidelines for query selection with and $or condition, or within a compound index as along as that data meets the rules for complexity of what can be combined. It isn't necessary for additional data fields to be indexed, but it is usually the most optimal way to query with addition query parameters.
I am trying to create a geospacial query in MongoDB that finds all circles (with varying radius) that overlap a single point.
My data looks something like this:
{
name: "Pizza Hut",
lat: <latitude>
lon: <longitude>
radius: 20
...
}
Basically, I am trying to do exactly what is described in this SO post but with MongoDB - Get all points(circles with radius), that overlap given point
geoIntersects (http://docs.mongodb.org/manual/reference/operator/query/geoIntersects/) looks like what I need. But in my case, the lat, lon, and radius is stored with each mongodb document and is not a fixed radius that is part of the query. Can this be done?
A different approach would be to find all documents whose distance from my query point is less than the value of their radius field (ie - 20km in the example above). How do you structure a MongoDB query where the calculated distance is part of the query filter criteria?
Thanks!
Well it would be nicer if you could use a GeoJSON object to represent the location but as of present the supported types are actually limited so a "Circle" type which would be ideal is not supported.
The closest you could do is a "Polygon" approximating a circle, but this is probably a little too much work to construct just for this query purpose. The other gotcha with doing this and then applying $geoIntersects is that the results will not be "sorted" by the distance from the query point. That seems to be the opposite of the purpose of finding the "nearest pizza" to the point of origin.
Fortunately there is a $geoNear operation added to the aggregation framework as of MongoDB 2.4 and greater. The good thing here is it allows the "projection" of a distance field in the results. This then allows you to do the logical filtering on the server to those points that are "within the radius" constraint to the distance from the point of origin. It also allows sorting on the server as well.
But you are still going to need to change your schema to support the index
db.places.insert({
"name": "Pizza Hut",
"location": {
"type": "Point",
"coordinates": [
151.00211262702942,
-33.81696995135973
]
},
"radius": 20
})
db.places.ensureIndex({ "location": "2dsphere" })
And for the aggregation query:
db.places.aggregate([
// Query and project distance
{ "$geoNear": {
"near": {
"type": "Point",
"coordinates": [
150.92094898223877,
-33.77654333272719
]
},
"distanceField": "distance",
"distanceMultiplier": 0.001,
"maxDistance": 100000,
"spherical": true
}},
// Calculate if distance is within delivery sphere
{ "$project": {
"name": 1,
"location": 1,
"radius": 1,
"distance": 1,
"within": { "$gt": [ "$radius", "$distance" ] }
}},
// Filter any false results
{ "$match": { "within": true } },
// Sort by shortest distance from origin
{ "$sort": { "distance": -1 } }
])
Basically this says,
*"out to 100 kilometers from a given location, find the places with their distance from that point. If the distance is within their "delivery radius" then return them, sorted by the closest"
There are other options you can pass to $geoNear in order to refine the result, as well as return more than the default 100 results if required and basically pass other options to query such as a "type" or "name" or whatever other information you have on the document.
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
}
}
}