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

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.

Related

Query an array of linked documents in Mongo using aggregates

I have the following collections.
interface PartnerOrganization extends Document {
retailLocations?: RetailLocations[];
}
interface RetailLocation extends Document {
location: {
type: string;
coordinates: [number];
};
}
RetailLocation has an appropriate index setup, and I can successfully run aggregate queries such as the following
const retailLocation = await RetailLocation.aggregate([
{
$geoNear: {
near: { type: 'Point', coordinates: [searchInput.longitude, searchInput.latitude] },
distanceField: 'dist.calculated',
maxDistance: Number(searchInput.radius),
includeLocs: 'dist.location',
spherical: true,
},
},
]);
I would like to be able to write an aggregate pipeline which uses a $geoNear aggregate function, against PartnerOrganizations.
The overall goal being that I can do a search for PartnerOrganizations that match certain $search (I am using the $search aggregate) criteria as well as location criteria.
The issue I am having is that $geoNear needs to be the first step in the aggregate pipeline, and as such retailLocations hasn't been populated at that stage. I have tested it out with $lookups, but doing anything before the $geoNear stage will cause a Mongo error similar to this -
Basically, my 'dream query' if you will, is something like this
const retailLocation = await PartnerOrganization.aggregate([
{
$lookup: {
from: 'retaillocations',
localField: 'retailLocations',
foreignField: '_id',
as: 'retailLocations',
},
},
{
$geoNear: {
key: 'retailLocations.location',
near: { type: 'Point', coordinates: [searchInput.longitude, searchInput.latitude] },
distanceField: 'dist.calculated',
maxDistance: Number(searchInput.radius),
includeLocs: 'dist.location',
spherical: true,
},
},
{
$search: {
index: 'Partner Organizations',
text: {
query: `*${searchInput.text}*`,
path: ['companyName', 'instagramBio', 'ogDescription'],
},
},
}
]);
But just not sure if this is possible, or if i have to do separate queries to make it work, then filter/map between the results. Just for claritys sake - I am using Linked Documents, not embedded - you can see what that looks like in Compass below.

MongoDB find documents using geo query depending on fields inside document

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.

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.

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