Mongoose within().circle() and $near gives result distinct to Mongo Query - node.js

I have a Node.js test in wich multiple Objects simulates to move away from some point in a map and Im countinuously testing if they´re within a radious from that point.
Each object corresponds to a Model with a nested legacy 2d Index 'location.loc'.
I have used this queries
var center={_lat:20,lng:-100};
var area = {
center: [center._lng,center._lat],
radius: 100,//This are supossed to be meters
unique: true,
spherical: true }
MyModel.where('location.loc')
.within()
.circle(area)
.exec(function (err, records) {
if (err) {
throw err;
}
//Log Length of records
});
And
MyModel.find({
"location.loc": {
$near: [center._lng,center._lat],
$maxDistance: 1 //This is suposed to be a mile
}
}).exec(function(err, documents) {
if (err) {
throw err;
}
//Log documents length
});
But both scripts returns me te entire collection of documents, even when they are miles away from the point.
At the same time im doing the same queries in my Mongo client with $near,$geoWithin and those queries gives me the right answer.
What is wrong with my Mongoose scripts?
Should only thest with within().circle() for this scenario?

Turn out that the radius in the first code are wrongly defined.
In this Mongo documentation says
With spherical: true, if you specify a GeoJSON point, MongoDB uses meters as the unit of measurement
But this is for a GeoJSON point and for geoNear.
For the legacy coordinate format [long,lat], we must divide the radius value in miles by 3963.2 to cast it as radians. See this Example.

Related

get Data from a collection in MongoDB using NodeJS

I am trying to get data from Mongo DB by filtering a nested object.
the collection structure is :
{
"id":"8820624457",
"type":"CreateEvent",
"actor":{
"id":27394937,
"login":"Johnson0608",
"display_login":"Johnson0608",
"gravatar_id":"",
"url":"https://api.github.com/users/Johnson0608",
"avatar_url":"https://avatars.githubusercontent.com/u/27394937?"
},
"repo":{
"id":163744671,
"name":"Johnson0608/test",
"url":"https://api.github.com/repos/Johnson0608/test"
},
"payload":{
"ref":"master",
"ref_type":"branch",
"master_branch":"master",
"description":null,
"pusher_type":"user"
},
"public":true,
"created_at":"2019-01-01T15:00:00Z"
}
I am trying to get data by repo id.
my code is :
collection.find({'repo.id':id}).toArray(function(err, docs) {
console.log(id);
assert.equal(err, null);
console.log("Found the following records");
console.log(docs);
res.status(200).json({docs});
callback(docs);
});
but I am getting empty array, would be grateful is someone can point me to the right direction
MongoDB compares types before values. If your id comes from req.params it's probably passed as string while repo.id seems to be a number. Try to convert your value to number:
const id = +req.params.repoId

How can I validate if gps coordinates given to a GET web service in node.js/mongodb are correct?

I have a webservice that queries the mongodb (with mongoose) with a given gps data, this is how it looks:
app.get('/queryUsers/:latitude,:longitude,:distance', function(req, res) {
var lat = req.params.latitude;
var long = req.params.longitude;
var distance = req.params.distance;
// Opens a generic Mongoose Query. Depending on the post body we will...
var query = HelpRequest.find({});
// ...include filter by Max Distance (converting miles to meters)
if (distance) {
// Using MongoDB's geospatial querying features. (Note how coordinates are set [long, lat]
query = query.where('location').near({
center: {type: 'Point', coordinates: [long, lat]},
// Converting meters to miles. Specifying spherical geometry (for globe)
maxDistance: distance * 1609.34, spherical: true
});
}
etc.
When I call it with a correct values, e.g.:
http://localhost:3000/queryUsers/48.77824506989009,19.80828625000005,1691.758035687216
then I'm getting the correct data. But when I call it for example with string:
http://localhost:3000/queryUsers/48.77824506989009,someString,1691.758035687216
then I'm getting this error:
{"stack":"Error\n at MongooseError.CastError
(/project/node_modules/mongoose/lib/error/cast.js:18:16)\n at SchemaArray.SchemaNumber.cast
(/project/node_modules/mongoose/lib/schema/number.js:219:9)\n at SchemaArray.castToNumber
(/project/node_modules/mongoose/lib/schema/array.js:227:38)\n at /project/node_modules/mongoose/lib/schema/array.js:237:29\n at Array.forEach (native)\n at castArraysOfNumbers
(/project/node_modules/mongoose/lib/schema/array.js:233:7)\n at cast$geometry (/project/node_modules/mongoose/lib/schema/array.js:260:7)\n at SchemaArray.cast$near
(/project/node_modules/mongoose/lib/schema/array.js:249:12)\n at SchemaArray.castForQuery
(/project/node_modules/mongoose/lib/schema/array.js:190:19)\n at module.exports
Now, since I'm new to writing such webservices - could you help me and tell me how should I modify my code to return a nicer message to the end user in case of giving the wrong data?
Maybe you can validate each of the numbers and return errors if they are not what you expect them to be, that way you can intercept the error before it happens in Mongoose which will be much faster since it doesn't hit the DB to do validation there.
Since lat and long are float numbers, you can validate if they are in fact, float numbers. The following link can help you with that.
How do I check that a number is float or integer?
To actually validate, you could use middleware or do it in the same method you're using but middleware is more "node.js".
app.get('/queryUsers/:latitude,:longitude,:distance', validateLocation, function(req, res) {
// data is correct here
});
and then create a new method to do the validation:
function validateLocation(req, res, next) {
var lat = req.params.latitude;
if(!isFloat(lat)) { return res.status(406).send("Please send a valid latitude"); }
// ... do the same for each variable. you can also use arrays to return multiple errors
else {
return next();
}
}

Mongoose/node.js How can i query in range [ elements between 20 and 30 ]

I have 500 elements in my mongodb table, I want to select for example only 100 elements after the 100 first elements. For this, try to use .slice etc.. but this query doesn't work correctly. I'm using mongoose and node.js:
var query2 = JenkinsTestModel.find();
query2.where('jobname date').slice([-100 /*skip*/, 100 /*limit*/]) //i tried several different ways here
query2.exec(function (err, job) {
if (err) throw err;
console.log(job);
});
This query is returning all the elements. How do I solve the above problem?
You could use the skip() and the limit() methods for this:
var query2 = JenkinsTestModel.find()
.where('jobname date')
.skip(100)
.limit(100)
.exec(function (err, job) {
if (err) throw err;
console.log(job);
});
Note: From the docs
The cursor.skip() method is often expensive because it requires the
server to walk from the beginning of the collection or index to get
the offset or skip position before beginning to return result. As
offset (e.g. pageNumber above) increases, cursor.skip() will become
slower and more CPU intensive. With larger collections, cursor.skip()
may become IO bound.

Multiple near with mongoose

I have the following "query":
MySchema
.where('address1.loc').near({
center: {
type: 'Point',
coordinates: user.address1.loc
},
maxDistance: 10 * 1000
}).where('address2.loc').near({
center: {
type: 'Point',
coordinates: user.address2.loc
},
maxDistance: 10 * 1000
})
.exec(function(err, objects) {
console.log(err);
console.log(objects);
if(err) return eachCallback(err);
return eachCallback();
});
My schema has two addresses (one pickup- and one handover-address). So I have to use two "nears". But this doesn't seem to be possible:
{ [MongoError: Can't canonicalize query: BadValue Too many geoNear expressions] name: 'MongoError' }
What are my alternatives?
Update:
I talked to some guys from MongoDB. Although my use case for this is valid, this doesn't seem to be possible out-of-the-box. So I'm looking for a "workaround". If you need details about the use case, let me know.
And here is how I defined the location inside my "addresses":
...
loc: {type: [Number], index: '2dsphere'},
...
I had encountered the same issue and error message. But I cannot remember exactly how I could overcome. I hope we can overcome your issue!
If your schema definition like the following, please try to the below solution;
loc : {
'type': { type: String, default: 'Point' },
coordinates: [Number]
}
Could you check address.loc.coordinates stores as number on your collection?
Alternate way
Try to use $geoWithin operator
I think you can change your questioning clauses like the following. You should use $geoWithin and $centerSphere instead of $near and $maxDistance. You've tried to find records that have loc fields in 10.000 meters proximity. $centerSphere indicates radius, it uses legacy coordinate values (only [longitude, latitude]) and it can used with geoJSON field and 2dsphere index. And your $centerSphere definition must be 10/6371 for 10 km. (tutorial).
If you use a second operator with $near operator it occurs a problem on MongoDB side.
You cannot combine the $near operator, which requires a special geospatial index, with a query operator or command that uses a different type of special index. For example you cannot combine $near with the $text query.
var r = 10/6371;
var area1 = { center: address1.loc.coordinates, radius: r, unique: true }
var area2 = { center: address2.loc.coordinates, radius: r, unique: true }
MySchema
.where('address1.loc').
.within()
.circle(area1)
.where('address2.loc').
.within()
.circle(area2)
.exec(function(err, objects) {
console.log(err);
console.log(objects);
if(err) return eachCallback(err);
return eachCallback();
});
Hope this helps..

Near operator for geojson point returning error when maxdistance is used in query

I am trying to store some geojson points in mongo db.Here is the mongoose schema I have defined.
new mongoose.Schema({
itemName:String,
loc:{ type: [Number], index: '2dsphere'}
});
Next I am trying to run a near operator to find out some points nearby.This is how I have defined the near query.
Model.where('loc').near({ center: { type:"Point",coordinates: [10,10] }, maxDistance: 20 }).exec(function(err,data){
console.log(err);
if (!err && data) {
console.log("Success");
} else {
console.log("Error");
}
});
But this is returning an error value as follows:
{ [MongoError: Can't canonicalize query: BadValue geo near accepts
just one argu ment when querying for a GeoJSON point. Extra field
found: $maxDistance: 20] name : 'MongoError' }
If i remove the maxDistance it is returning all the collection elements.
Any idea why this error is coming?Thanks in advance for any help
Mongoose is still using the 'geoNear' database command form. This is considered obsolete in all ongoing versions of MongoDB.
Use the standard query form instead, which has been integrated with the standard query engine since MongoDB 2.6 and greater versions:
Model.find({
"loc": {
"$near": {
"$geometery": {
"type": "Point",
"coordinates": [ 10,10 ],
},
"$maxDistance": 20
}
}
},function(err,docs) {
// do something here
});
It's JavaScript, a "dynamically typed language". You don't need these ridiculous function helpers that are needed for strict typed languages with no dynamic constructs for defining and Object structure.
So do what the manual (which all examples are in JSON notation, which JavaScript natively understands) tells you to do and you are always fine.

Resources