MongoDB find documents using geo query depending on fields inside document - mongodb

The following is an example of a MongoDB document:
{
radius: 5000,
location: {
type: 'Point',
coordinates: [60.1241, 12.12454351] // [long, lat]
}
}
Now I want to be able to query/find all documents for which a given point p = [long, lat] falls inside the radius given by the circle with center location.coordinates and radius radius.
The best I came up with is this
find({
"location": {
$geoWithin: {
$centerSphere: [p, 5000],
},
},
});
but I do not know how to get the radius to not be hardcoded but be from the document field.

I found a similar question and created a working solution to my problem from that. (Geospatial $near within current document field value)
You have to add an index of 2dsphere first. (https://docs.mongodb.com/manual/core/2dsphere/)
Then use the following aggregation:
aggregate([
{
$geoNear: {
near: {
type: "Point",
coordinates: [60.1241, 12.12454351],
},
distanceField: "distance",
maxDistance: 40000, // optional (can be set if you know the max radius)
},
},
{
$redact: {
$cond: {
if: { $lte: ["$distance", "$radius"] },
then: "$$KEEP",
else: "$$PRUNE",
},
},
},
]);
You first calculate and add a new field distance. Then you only keep the documents that have a distance lte the radius.

Related

Does geoNear aggregation not work when the query field is the objectId?

My geonear code work except when I put query: {id: req.params.id}. It works for any other filter obj I put.
Does anyone know how to query for a certain document using the objectId while using geoNear?
I presently have what's below. Is there also any way to do the matching on the document first i.e {$match: {id: req.params.id}. I tried doing this but since $geoNear has to be the first step in the pipeline it didn't work out.
const distances = await User.aggregate([
{
$geoNear: {
near: {
type: "Point",
coordinates: [lng, lat],
},
// maxDistance: 13.3333 * 1000,
spherical: true,
distanceField: "distance",
distanceMultiplier: 0.001,
query: { _id: req.params.id },
},
},
{ $project: { id: 1, distance: 1 } },
]);
unable to use $match operator for mongodb/mongoose aggregation with ObjectId ^ This fixed it sorry!

Question for using $geoNear twice in mongodb

I want to make a mongodb query to search companies by applying following filter.
{
myLocation: [lng1, lat1], // That is to get distance from current location to companies on result.
region: [lng2, lat2], //That is to get companies within a radius in this region
radius: 10000,
tags: ["tag1", "tag2"],
sort: "asc" // to sort by nearest from current location.
}
I thought it needs to use $geoNear twice and made an aggregation like this.
{
$geoNear: {
near: {
type: "Point",
coordinates: myLocation
},
distanceField: 'distance1',
maxDistance: radius,
spherical: true,
},
$match: { tags: tags },
$geoNear: {
near: {
type: "Point",
coordinates: region
},
distanceField: 'distance2',
spherical: true,
}
}
but it occurs an error - $geoNear is only valid as the first stage in a pipeline.
Is there any way to make a query to work this filter.
Appreciate your help.

MongoDB geoNear returning blank when paginating

Im trying to bring back a list of profiles. This worked fine used find()
But I needed to switch to aggregate for distance sorting.
Now instead of getting my full 100 record by 20 each. I get 40 and it's as if it doesnt find the rest.
Any help?
(yes I have tried with a simple geoNear filter. Same result)
await Profile.aggregate([
{
$geoNear: {
near: {
type: "Point",
coordinates: [long, lat]
},
distanceMultiplier:
req.user.distanceMetric === "km" ? 0.001 : 0.000621371, // meter to ki:miles
distanceField: "distance",
spherical: true,
maxDistance: distance !== 100 ? distance * 1609.34 : 99999999999
}
},
{
$match: {
$and: [
{
_id: {
$ne: Profile.castID(req.user.profileID),
$nin: doNotDisplayList.map(id => Profile.castID(id))
}
}
]
}
},
{ $skip: skip },
{ $limit: limit }
]).sort({
online: -1
});

Better way to query multiple fields in $geoNear than using $or?

I have a list of events. I would like to search both the title and description fields for a certain phrase and return events in a given radius matching the query.
I am currently using the $or operator, which seems to work. However, I am wondering if there is a better way of doing this? I've created a compound text index that uses both fields; I'm just not sure if it actually gets used.
let queryText = /someString/;
return db.collection('events').aggregate([
{
$geoNear: {
near: [lng, lat],
distanceField: 'distance',
maxDistance: radius,
query: {
$or: [
{title: queryText},
{description: queryText}
]
},
spherical: true
}
}
]).toArray();
You can include your query in another argument (remember that $geoNear always must be on top) like this
let queryText = /someString/;
return db.collection('events').aggregate([
{
$geoNear: {
near: [lng, lat],
distanceField: 'distance',
maxDistance: radius,
spherical: true
},
{
$match: {
$or: [
{title: queryText},
{description: queryText}
]
}
}
]).toArray();
All of the time I use this way, I have never try your way before.

Where $geoNear takes location field in mongodb?

I have used $near in match stage of aggregation framework, but in latest versions of mongodb it doesn't work. So I read the documentaion and can't find where to set the location field.
Here it is in near query:
{
<location field>: {
$near: {
$geometry: {
type: "Point" ,
coordinates: [ <longitude> , <latitude> ]
},
$maxDistance: <distance in meters>,
$minDistance: <distance in meters>
}
}
}
And here is the $geoNear query from example:
{
$geoNear: {
near: { type: "Point", coordinates: [ -73.99279 , 40.719296 ] },
distanceField: "dist.calculated",
minDistance: 2,
query: { type: "public" },
includeLocs: "dist.location",
num: 5,
spherical: true
}
}
What if I have two different location fields in one document? Don't understand how it may work.
prerequisite for geoNear:
You should provide a 2dsphere index for the collection
There must be only one 2dsphere index for that collection
Thus, we could conclude that geoNear will only pick the one and only column that is 2dsphere-indexed