I have a database with two collections like so:
[
{
"name": "Person A",
"location": {"type": "Point", "coordinates": [180, 90]}
},
{
"name": "Person B",
"location": {"type": "Point", "coordinates": [-180, -90]}
}
]
[
{
"name": "Store A",
"location": {"type": "Point", "coordinates": [180, 90]}
},
{
"name": "Store B",
"location": {"type": "Point", "coordinates": [-180, -90]}
}
]
For each person, I want to find the nearest place. I could get it to find the nearest place for one specific pair of coordinates, not for the entire collection. Is there any way to do that without using foreach?
This is the closest I got following the MongoDB documentation:
// Current $geoNear:
{
// Instead of having to give constants of a single
// point, I want to compare against all coordinates
// of another collection. ↓
near: {"type":"Point","coordinates":[-180, 90]},
distanceField: 'distance',
maxDistance: 50,
spherical: true
}
This can be achieved using aggregation.
[{
$lookup: {
from: "places",
let: {
"personPoint": "$location"
},
as: "nearestPlace",
pipeline: [
{
$geoNear: {
near: "$$personPoint",
spherical: true,
distanceField: "distance",
maxDistance: 50,
}
},
{
$unwind: "$location"
},
]
}
},
{
$unwind: {
path: "$nearestPlace",
preserveNullAndEmptyArrays: true
}
}]
I couldn't test it on playground because of geo index. So might require some minor fix. If anyone can make it work on playground heres the link
https://mongoplayground.net/p/aROX976gYzC
Related
When I use $geoNear I can return a calculated distance by including the "distanceField" which is extremely useful when displaying items and their distance from a location. My code for this is:
$geoNear: {
near: {
type: "Point",
coordinates: [
req.body.position.lng ,
req.body.position.lat
]
},
distanceField: "dist.calculated",
maxDistance: req.body.distance,
spherical: true
When using Atlas search, I need the same or similar "distanceField", but havn't been able to find a solution. I am open to other workarounds. Here's my $search pipeline:
"$search": {
"index": "searchResults",
"compound": {
"must": [
{
"text": {
"query": `${req.body.query}`,
path: [
"name",
"description",
"tag", ],
"fuzzy": {
"maxEdits": 2,
"prefixLength": 4
}
}
},
{
"geoWithin": {
"circle": {
"center": {
"type": "Point",
"coordinates": [
req.body.position.lng,
req.body.position.lat
]
},
"radius": req.body.distance,
},
"path": "location",
}
}
],
"filter":[{
"text": {
"query": "Active",
"path": "active",
}
}]
}
}
}```
How to use $geoNear in mongodb?
I want to use geoNear 3 times and i want to get all result.
I try to made an aggregationlike this.
but it occurs an error "$geoNear requires a 'near' option as an Array"
Thank you for help
db.getCollection('collection').aggregate([
{
"$geoNear": {
"$or": [
{
"near": {
"type": "Point",
"coordinates": [
126.7384307,
35.9672442
]
},
"maxDistance": 1000,
"query": {
"distance": 1000,
"use_noti": true,
},
"distanceField": "location",
},
{
"near": {
"type": "Point",
"coordinates": [
126.7384307,
35.9672442
]
},
"maxDistance": 5000,
"query": {
"distance": 5000,
"use_noti": true,
},
"distanceField": "location",
},
]
}
},
])
```
I have two collections, which both have Geospatial Indexes:
people
[
{
"name": "Steve",
...
"geometry": {"type": "Point", "coordinates": [90, 90]}
},
{
"name": "John",
...
"geometry": {"type": "Point", "coordinates": [-90, -90]}
}
]
zones
[
{
"zone": "Place_0001001",
"geometry":
{
"type": "Polygon",
"coordinates": [
[90.0001, 90.0001],
[90.0002,90.0000],
...
]
},
"avg_income": 9999,
"avg_age": 50
]
For analysis purposes I need the Zone information on a Person level, which requires to lookup the nearest Zone to each Person and then retrieve the fields.
I haven't been able to assign the nearest Zone to a Person, I understand the basis of the code should be something like this, a geoNear with a limit of 1:
db.people.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [90,90]},
spherical: true,
distanceField: "distance"
},
},
{
$limit: 1,
},
]);
But I'm unsure on how to both reference the Zone and add it to the People collection.
I want to create a new location field from already existing longitude and latitude.
db.neigborhood.updateMany({}, {
$set: {
"location": {
"type": "Point",
"coordinates": ["$longitude", "$latitude"]
}
}});
I wrote this code that should create the new field, but the problem is that instead of the field values I get the names as strings.
{
"_id": {
"$oid": "626a01f1df85b4b2937ece2d"
},
"latitude": "10.4980067",
"longitude": "-66.8335096",
"location": {
"type": "Point",
"coordinates": [
"$longitude",
"$latitude"
]
}
}
What am I doing wrong that I get "$longitude" instead of the -66.8335096 value?
Works with Update with Aggregation Pipeline.
db.neigborhood.updateMany({},
[
{
$set: {
"location": {
"type": "Point",
"coordinates": [
"$longitude",
"$latitude"
]
}
}
}
])
Sample Mongo Playground
I am creating a carpooling app that offers a list of trips (Departure City -> Arrival City).
I type the desired departure and arrival coordinates. And I get back the best options
My goal is to create a mongo request that return best routes that comes closest to my departure address and my arrival address
Example:
Departure Sèvres coordinates: [ 2.210590 , 48.824169 ]
Arrival Capbreton coordinates: [ -1.431370 , 43.640080 ]
I tried to combine this with $and operator but I'm not sure that is the solution... ("Too many geoNear expressions")
db.trip.find({
$and: [
{
"departureLocation": {
$near: {
$geometry: {
type: "Point",
coordinates: [ 2.210590 , 48.824169 ]
},
}
}
},
{
"arrivalLocation": {
$near: {
$geometry: {
type: "Point",
coordinates: [ -1.431370 , 43.640080 ]
},
}
}
}
]
}, {"departure": 1, "arrival": 1})
Here my trips
[
{
"_id": "5d24d2e4ea5e2a29ea0f0e77",
"departure": "Paris",
"arrival": "Givrand",
"departureLocation": {
"type": "Point",
"coordinates": [
2.352222,
48.856613
]
},
"arrivalLocation": {
"type": "Point",
"coordinates": [
-1.88465,
46.67119
]
},
},
{
"_id": "5d3c594e6562967b8ad9e62b",
"departure": "Bordeaux",
"arrival": "Biarritz",
"departureLocation": {
"type": "Point",
"coordinates": [
-0.57918,
44.837788
]
},
"arrivalLocation": {
"type": "Point",
"coordinates": [
-1.558626,
43.48315
]
},
},
{
"_id": "5d3c59e96562967b8ad9e62c",
"departureLocation": {
"type": "Point",
"coordinates": [
2.18919,
48.810032
]
},
"departure": "Chaville",
"arrival": "Seignosse",
"arrivalLocation": {
"type": "Point",
"coordinates": [
-1.37524,
43.69011
]
},
},
{
"_id": "5d3c5a8a6562967b8ad9e62d",
"departureLocation": {
"type": "Point",
"coordinates": [
-1.553621,
47.218372
]
},
"departure": "Nantes",
"arrival": "Hossegor",
"arrivalLocation": {
"type": "Point",
"coordinates": [
-1.3952,
43.663342
]
},
}
]
Expected result :
(Chaville - Seignosse) should be placed at the first position of the result because it's the best option if I'm looking for a ride (Sèvres - Capbreton)
Unfortunately for you, there's no mongodb-only solution to resolve this as:
Only one $geonear expression can be used in a find() method.
Only the first stage of an aggregation can be a $geonear stage.
$geonear can not be used inside a $facet stage.
You have to deal with this programmatically, to run 2 separate geonear queries on your collection and find the best of the both resultsets. Before doing this, think about what is 'the best' result (closest to departure, arrival, lowest mean of both, etc...)