Mongoose get all Elements where a precalculation matches [duplicate] - node.js

When I am firing this query on MongoDB, I am getting all the places in the proximity of 500 miles to the specified co-ordinates. But I want to know the exact distance between the specified co-ordinates and the result location.
db.new_stores.find({ "geometry": { $nearSphere: { $geometry: { type: "Point", coordinates: [ -81.093699, 32.074673 ] }, $maxDistance: 500 * 3963 } } } ).pretty()
My Output looks like:
{
"_id" : ObjectId("565172058bc200b0db0f75b1"),
"type" : "Feature",
"geometry" : {
"type" : "Point",
"coordinates" : [
-80.148826,
25.941116
]
},
"properties" : {
"Name" : "Anthony's Coal Fired Pizza",
"Address" : "17901 Biscayne Blvd, Aventura, FL"
}
}
I also want to know the distance of this place from the specified co-ordinate. I created 2dsphere index on geometry.

You can use the $geoNear aggregate pipeline stage to produce a distance from the queried point:
db.new_stores.aggregate([
{ "$geoNear": {
"near": {
"type": "Point",
"coordinates": [ -81.093699, 32.074673 ]
},
"maxDistance": 500 * 1609,
"key" : "myLocation",
"spherical": true,
"distanceField": "distance",
"distanceMultiplier": 0.000621371
}}
]).pretty()
This allows you to specify "distanceField" which will produce another field in the output documents containing the distance from the queried point. You can also use "distanceMultiplier" to apply any conversion to the output distance as required ( i.e meters to miles, and noting that all GeoJSON distances are returned in meters )
There is also the geoNear command with similar options, but it of course does not return a cursor as output.
if you have more than one 2dsphere, you should specify a "key".

MongoDB provides a $geoNear aggregator for calculating the distance of documents in a collection with GeoJson coordinates.
Let us understand it with a simple example.
Consider a simple collection shops
1. Create Collection
db.createCollection('shops')
2. Insert documents in shops collections
db.shops.insert({name:"Galaxy store",address:{type:"Point",coordinates:[28.442894,77.341299]}})
db.shops.insert({name:"A2Z store",address:{type:"Point",coordinates:[28.412894,77.311299]}})
db.shops.insert({name:"Mica store",address:{type:"Point",coordinates:[28.422894,77.342299]}})
db.shops.insert({name:"Full Stack developer",address:{type:"Point",coordinates:[28.433894,77.334299]}})
3. create GeoIndex on "address" fields
db.shops.createIndex({address: "2dsphere" } )
4. Now use a $geoNear aggregator
to find out the documents with distance.
db.shops.aggregate([{$geoNear:{near:{type:"Point",coordinates:[28.411134,77.331801]},distanceField: "shopDistance",$maxDistance:150000,spherical: true}}]).pretty()
Here coordinates:[28.411134,77.331801] is the center position or quired position from where documents will be fetched.
distanceField:"shopDistance" , $geoNear Aggregator return shopDistance as fields in result.
Result:
{ "_id" : ObjectId("5ef047a4715e6ae00d0893ca"), "name" : "Full Stack developer", "address" : { "type" : "Point", "coordinates" : [ 28.433894, 77.334299 ] }, "shopDistance" : 621.2848190449148 }
{ "_id" : ObjectId("5ef0479e715e6ae00d0893c9"), "name" : "Mica store", "address" : { "type" : "Point", "coordinates" : [ 28.422894, 77.342299 ] }, "shopDistance" : 1203.3456146763526 }
{ "_id" : ObjectId("5ef0478a715e6ae00d0893c7"), "name" : "Galaxy store", "address" : { "type" : "Point", "coordinates" : [ 28.442894, 77.341299 ] }, "shopDistance" : 1310.9612119555288 }
{ "_id" : ObjectId("5ef04792715e6ae00d0893c8"), "name" : "A2Z store", "address" : { "type" : "Point", "coordinates" : [ 28.412894, 77.311299 ] }, "shopDistance" : 2282.6640175038788 }
Here shopDistance will be in meter.

maxDistance -> Optional. The maximum distance from the center point that the documents can be. MongoDB limits the results to those documents that fall within the specified distance from the center point.
Specify the distance in meters if the specified point is GeoJSON and in radians if the specified point is legacy coordinate pairs.
In the docs it says if you use legacy pairs , eg : near : [long , lat] , then specify the maxDistance in radians.
If you user GeoJSON , eg : near : { type : "Point" , coordinates : [long ,lat] },
then specify the maxDistance in meters.

Use $geoNear to get the distance between a given location and users.
db.users.aggregate([
{"$geoNear": {
"near": {
"type": "Point",
"coordinates": [ longitude, latitude]
},
"distanceField": "distance",
"distanceMultiplier": 1/1000,
"query": {/* userConditions */},
}}
]).pretty()

Related

Find circles that intersects a point [duplicate]

This question already has an answer here:
How to define a circle for a mongo db schema?
(1 answer)
Closed 6 years ago.
I'm getting in trouble when I try to run this code on mongodb
var partners = db.partners.find({})
var kmToRadius = function(km){
var earthRadiusInKm = 6378.1;
return km / earthRadiusInKm;
}
db.runCommand({
$centerSphere: [ [partners.loc], kmToRadius(partners.km) ] :{
$geoIntersects:{
$geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] }
}
}
})
What I'm trying to do is get all the partners location (which are in geojson format), make a circle using $centerSphere and verify if there is intersection with a coordinate.
I know I can't store circles in GeoJson format, only polygons, which turns very difficult to do what I want. Someone knows if there is another way to make this work ? Thanks
My partners collection seems like this:
{
"_id" : ObjectId("583315cfa9d41218cc9c833f"),
"updatedAt" : ISODate("2016-11-21T15:42:07.703Z"),
"createdAt" : ISODate("2016-11-21T15:42:07.703Z"),
"name" : "partnerName",
"mainEmail" : "email",
"password" : "$2a$10$WJC6WzZNM8NyDKQgovJa.OICLOMV6Qp6xcGLE3fRcUGuBa8Zhy8qy",
"km" : 10,
"loc" : {
"type" : "Point",
"coordinates" : [
-46.62217,
-23.668224
]
},
"rate" : 4,
"nServices" : 35
}
But what I want to do is create a radius for each partner and check which partners intersects a point, instead of get the partners within a radius.

MongoDB remove the lowest score, node.js

I am trying to remove the lowest homework score.
I tried this,
var a = db.students.find({"scores.type":"homework"}, {"scores.$":1}).sort({"scores.score":1})
but how can I remove this set of data?
I have 200 pieces of similar data below.
{
"_id" : 148,
"name" : "Carli Belvins",
"scores" : [
{
"type" : "exam",
"score" : 84.4361816750119
},
{
"type" : "quiz",
"score" : 1.702113040528119
},
{
"type" : "homework",
"score" : 22.47397850465176
},
{
"type" : "homework",
"score" : 88.48032660881387
}
]
}
you are trying to remove an element but the statement you provided is just to find it.
Use db.students.remove(<query>) instead. Full documentation here

MongoDB query using $near not working when nested

I have several documents in my Articles collection. Every document has a location value and some extra data. The location value looks like this:
"loc" : {
"type" : "Point",
"coordinates" : [
4,
54
]
}
I can build an index by executing the following command:
db.articles.ensureIndex({loc:"2dsphere"});
And I can query documents based on their location and a $maxDistance with the following query:
db.articles.find({ loc : { $near : {$geometry : {type : "Point" , coordinates : [4, 54] }, $maxDistance : 1000 } } });
This works perfectly!
However when I change the location of my "loc" object in my document, my query always returns zero results. My document should look like this (This is a minimized version):
{
"articledata" {
"content": {
"contact": {
"loc" : {
"type" : "Point",
"coordinates" : [
4.1,
54
]
}
}
}
}
}
When I rebuild my index query:
db.articles.ensureIndex({"articledata.content.contact.loc":"2dsphere"});
and execute my query again after changing my 'loc' location in the document:
db.articles.find({ "articledata.content.contact.loc" : { $near : {$geometry : {type : "Point" , coordinates : [4, 54] }, $maxDistance : 10000 } } });
There are no results.
It's probably some stupid mistake but I really can't find the problem...
Is there anyone who can help me out?
Thanks in advance!

Using near with elemMatch in Mongoose

I am searching within a collection of Stores. Stores have an embedded collection of outlets with locations. My goal is to return the set of stores that have outlets near a geolocation, and also only return those Outlets within that location.
I can successfully restrict the query to only return Stores have an Outlet at a particular location using 'near'
Store
.where('isActive').equals(true)
.where('outlets.location')
.near({ center: [153.027117, -27.468515], maxDistance: 1000 / 6378137, spherical: true })
.where('outlets.isActive').equals(true)
.where('products.productType').equals('53433f1f3e02e39addde1954')
.where('products.isActive').equals(true)
.select('name outlets')
.select({'products': {$elemMatch: {'isActive': true, 'productType': '53433f1f3e02e39addde1954'}}})
.select('name outlets')
.execQ()
.then(function (results) {
console.log(results);
})
.fail(function (err) {
console.log(err);
})
.done();
The problem I have is that the store document returns all the outlets, not just the outlet that matched the geolocation. I've tried using elemMatch within a select like I did with the products;
.select({'outlets': {$elemMatch: {'location': {near:{ center: [153.027117, -27.468515], maxDistance: 10000 / 6378137, spherical: true }}}}})
However it returns an empty array. Can use use the near operator in an elemMatch clause? Am I doing it incorrectly? Is there an more efficient/fast/better way to achieve the goal?
I see what you are trying to do here but there seems to be a few flaws in this sort of design. Though not exactly your document structure I see you are trying to do something like this:
{
"_id" : ObjectId("5344badd519563414f23fdf8"),
"store" : "Mine",
"outlets" : [
{
"name" : "somewhere",
"loc" : {
"type" : "Point",
"coordinates" : [
150.975131,
-33.8440366
]
}
},
{
"name" : "else",
"loc" : {
"type" : "Point",
"coordinates" : [
151.3651524,
-33.8389783
]
}
}
]
}
{
"_id" : ObjectId("5344be6f519563414f23fdf9"),
"store" : "Another",
"outlets" : [
{
"name" : "else",
"loc" : {
"type" : "Point",
"coordinates" : [
151.3651524,
-33.8389783
]
}
},
{
"name" : "somewhere",
"loc" : {
"type" : "Point",
"coordinates" : [
150.975131,
-33.8440366
]
}
}
]
}
So basically you appear to be attempting to nest the outlet locations within an array in a top level document.
What I am referring to a flaw here is that by design, any type of "near" based query is going to return more than 1 result. That does seem logical when you look at the purpose. You can of course modify this to restrict the results by "maxDistance" but generally it will be more than 1.
So the only way is to .limit() the results returned by the cursor to a single "nearest" response. Also note that with some operations those results are not necessarily "sorted" with the "nearest response first.
Now as these results are actually contained within an array of the document, remember that .find() itself does not actually "filter" the results of an array, so of course the document will contain all of the array contents.
If you tried to "project" with a positional $ operator, then the problem falls back to the original point because there is no singular actual match, so it is not possible to return an "index" value for the matching element. If you in fact did try this, you would always get the default index value of 0, so just returning the first element.
If then you thought you could run off to aggregate and and try to actually "de-normalize" the array entries, you would be out of luck because due to the need to use the index at the first stage of any aggregation pipeline statement.
So the summary of this is that embedded entries like this are not suited to this design where you need to do geo-spatial matching on those store locations. The locations are better off in a separate collection:
{
"_id" : ObjectId("5344bec7519563414f23fdfa"),
"store": "Mine"
"name" : "else",
"loc" : {
"type" : "Point",
"coordinates" : [
151.3651524,
-33.8389783
]
}
}
{
"_id" : ObjectId("5344bed5519563414f23fdfb"),
"store": "Mine"
"name" : "somewhere",
"loc" : {
"type" : "Point",
"coordinates" : [
150.975131,
-33.8440366
]
}
}
So that would allow you to "limit" the result to the "nearest" match by setting the limit to 1. You can also include any necessary values such as the "store" to be used in your filtering. If you need to you can include other information aside from what you need to filter or otherwise just put the ObjectId values within the array of the original object, or possibly even duplicate for both collections.
But since the very nature of these queries is intended to not only return 1 match, then there is no way you are going to get this to work on embedded documents. So your solution will require some changes in your overall schema.

MongoDB geospatial index, how to use it with array elements?

I would like to get Kevin pub spots near a given position. Here is the userSpots collection :
{ user:'Kevin',
spots:[
{ name:'a',
type:'pub',
location:[x,y]
},
{ name:'b',
type:'gym',
location:[v,w]
}
]
},
{ user:'Layla',
spots:[
...
]
}
Here is what I tried :
db.userSpots.findOne(
{ user: 'Kevin',
spots: {
$elemMatch: {
location:{ $nearSphere: [lng,lat], $maxDistance: d},
type: 'pub'
}
}
},
},
function(err){...}
)
I get a strange error. Mongo tells me there is no index :2d in the location field. But when I check with db.userSpots.getIndexes(), the 2d index is there. Why doesn't mongodb see the index ? Is there something I am doing wrong ?
MongoError: can't find special index: 2d for : { spots: { $elemMatch: { type:'pub',location:{ $nearSphere: [lng,lat], $maxDistance: d}}}, user:'Kevin'}
db.userSpots.getIndexes() output :
{
"0" : {
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "mydb.userSpots",
"name" : "_id_"
},
"1" : {
"v" : 1,
"key" : {
"spots.location" : "2d"
},
"ns" : "mydb.usersBoxes",
"name" : "spots.location_2d",
"background" : true,
"safe" : null
}
}
For a similar geospatial app, I transformed the location into GeoJSON:
{
"_id" : ObjectId("5252cbdd9520b8b18ee4b1c3"),
"name" : "Seattle - Downtown",
"location" : {
"type" : "Point",
"coordinates" : [
-122.33145,
47.60789
]
}
}
(the coordinates are in longitude / latitude format. Mongo's use of GeoJSON is described here.).
The index is created using:
db.userSpots.ensureIndex({"location": "2dsphere"})
In my aggregation pipeline, I find matches using:
{"$match":{"location":{"$geoWithin": {"$centerSphere":[[location.coordinates[0], location.coordinates[1]], radius/3959]}}}}
(where radius is measured in miles - the magic number is used to convert to radians).
To index documents containing array of geo data MongoDB uses multi-key index. Multi-key index unwinds document to some documents with single value instead of array before indexing. So the index consider that key field as single value field not array.
Try query it without $elemMatch operator.

Resources