mongodb - how to pass a variable field in geoNear? - mongodb

coordinates are stored in array
const userLocArray = userLoc.split(',');
How to use this array in geoNear coordinates?
userLocArray[0], userLocArray[1] does not work
$geoNear: {
near: { type: "Point", coordinates: [userLocArray[0], userLocArray[1]] },
distanceField: "calculatedDist",
spherical: true
}
On the client side:
const userLoc = currentUser.location.coordinates;
console.log(userLoc)//this is [31.4998, -61.4065]
let { data: matches } = useSWR(`/api/myapi?userIdToMatch=${_id}&userLoc=${userLoc}&page=${matchIndex}`, fetcher,);
In the api
handler.get(async (req, res) => {
const {userIdToMatch, userLoc} = req.query;
const userLocArray = userLoc.split(',');

coordinates is an array of numbers, you are passing strings. Try this:
$geoNear: {
near: { type: "Point", coordinates: [parseFloat(userLocArray[0]), parseFloat(userLocArray[1])] },
distanceField: "calculatedDist",
spherical: true
}
You can also use Number instead of parseFloat.

Related

Mongo geoWithin error: Polygon coordinates must be an array

I have a data set with geo points.
{ _id ...other fields... location: { type: "Point", coordinates: [0,0]}}
What I have been attempting to do is filter out and delete any documents that have points that are in water bodies. I downloaded and converted a shape file of the earth's water bodies and stored that in a separate collection in the same database.
I have been trying to use Mongo's geoWithin function, but am not able to get it to work for me when I specify the water body's polygon document. If I hard code a polygon it works, but I don't really want to type in all the earth's water polygons into my code...
This doesn't work:
var geo = {type: "Point", coordinates: [0,0]}
db.waterBodies.find({
geo: {
$geoWithin: {
$geometry: {
type: 'Polygon',
coordinates: "$geometry.coordinates"
}
}
}
}).count()
or this
var geo = {type: "Point", coordinates: [0,0]}
var poly = [[[0,0],[0,3],[3,0],[0,0]]]
db.data.find({
geo: {
$geoWithin: {
$geometry: {
type: 'Polygon',
coordinates: "$poly"
}
}
}
}).count()
It generates this error:
E QUERY [js] uncaught exception: Error: count failed: { "ok" : 0, "errmsg" : "Polygon coordinates must be an array", "code" : 2,
"codeName" : "BadValue" } :
_getErrorWithCode#src/mongo/shell/utils.js:25:13 DBQuery.prototype.count#src/mongo/shell/query.js:376:11 #(shell):1:1
This works and doesn't throw an error but requires hard coded values:
var geo = {type: "Point", coordinates: [0,0]}
db.data.find({
geo: {
$geoWithin: {
$geometry: {
type: 'Polygon',
coordinates: [[[0,0],[0,3],[3,0],[0,0]]]
}
}
}
}).count()
and this
db.data.find({
'location.coordinates': {
$geoWithin: {
$geometry: {
type: 'Polygon',
coordinates: [[[0,0],[0,3],[3,0],[0,0]]]
}
}
}
}).count()
I of coarse don't want the count but used that for testing purposes.
The simple answer for me would look something like this:
const polygons = await getPolygons(); //get all the polygons from the water body's collection
const filter = {
'location.coordinates': { //the points I want to filter
$geoWithin: { //could also be geoIntersects
$geometry: {
type: 'MultiPolygon',
coordinates: polygons.geometry.coordinates //the water body polygons
}
}
}
};
try {
await db.collection(collection).deleteMany(filter);
} catch (e) {
if (e instanceof MongoError) {
Logger.info('Error deleting log');
throw e;
}
}
I would want to use multipolygon since there are many water bodies.
So far I have read everything I can find on google but nothing has worked for me. All the examples I have found hard code an array for the coordinates, but I don't want to do this.
Please help and let me know if there is a way to do this or to remove all points that are not found on land.
Thanks in advance.
Does this work for you?
db.data.insert({
geo: {
type: "Point",
coordinates: [0,0]
}
})
db.polygons.insert({
geo: {
type: "Polygon",
coordinates: [[[0,0],[0,3],[3,0],[0,0]]]
}
})
var polygon = db.polygons.findOne()
db.data.find({
geo: {
$geoWithin: {
$geometry: {
type: 'Polygon',
coordinates: polygon.geo.coordinates
}
}
}
}).count()

Empty array response to Get request

I am following a full-stack web development guide. The git repository can be found here:
https://github.com/cliveharber/gettingMean-2/tree/chapter-06
In chapter 6, I've created an API that is supposed to display a list of locations based on the GPS coordinates. When I test the get request I get an empty array. The get request URL is:
http://localhost:3000/api/locations?lat=51.455041&lng=-0.9690884
This is the controller code for locations:
Note that I use a Mongoose aggregate called $geonear to find a list of locations close to a specified point
const locationsListByDistance = async (req, res) => {
const lng = parseFloat(req.query.lng);
const lat = parseFloat(req.query.lat);
const near = {
type: "Point",
coordinates: [lng, lat]
};
const geoOptions = {
distanceField: "distance.calculated",
key: 'coords',
spherical: true,
maxDistance: 20000
};
if (!lng || !lat) {
return res
.status(404)
.json({ "message": "lng and lat query parameters are required" });
}
try {
const results = await Loc.aggregate([
{
$geoNear: {
near,
...geoOptions
}
}
]);
const locations = results.map(result => {
return {
id: result._id,
name: result.name,
address: result.address,
rating: result.rating,
facilities: result.facilities,
distance: `${result.distance.calculated.toFixed()}m`
}
});
res
.status(200)
.json(locations);
} catch (err) {
res
.status(404)
.json(err);
}
};
This is my location model:
const locationSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
address: String,
rating: {
type: Number,
'default': 0,
min: 0,
max: 5
},
facilities: [String],
coords: {
type: {type: String},
coordinates: [Number]
},
openingTimes: [openingTimesSchema],
reviews: [reviewSchema]
});
I am sure I use the right GPS coordinates in the get request URL. This the document I am trying to retrieve from the database:
I am not sure why I'm getting an empty array when testing this API. Are there any issues in my code?
If I'm reading your code right, the aggregation that you are sending is:
Loc.aggregate([
{
$geoNear: {
{
type: "Point",
coordinates: [lng, lat]
},
distanceField: "distance.calculated",
key: 'coords',
spherical: true,
maxDistance: 20000
}
}
]);
You haven't mentioned creating a 2dsphere index on the coords field of the collection, I'll assume you have done that.
That aggregation seems to be missing the near field name, like:
Loc.aggregate([
{
$geoNear: {
near: {
type: "Point",
coordinates: [lng, lat]
},
distanceField: "distance.calculated",
key: 'coords',
spherical: true,
maxDistance: 20000
}
}
]);

I couldn't able to fetch the records by using latitude and longitude, using Mongodb

I'm trying to fetch the records based on latitude and longitude using mongodb. I've gone through many examples nothing worked out for me.
Here is my Schema structue.
latlang: {
type: { type: String, default: 'Point'},
coordinates: [Number]
}
After storing the values it is looking like
latlang:{
type: "Point",
coordinates: [77.6836, 12.8486]
}
I'm setting index for the latlang field like
schema.index({ 'latlang.coordinates' : '2dsphere' });
I've multiple records like as below
latlang:{
type: "Point",
coordinates: [77.6836, 12.8486]
}
latlang:{
type: "Point",
coordinates: [77.5712, 12.9766]
}
latlang:{
type: "Point",
coordinates: [77.6174, 12.9226]
}
when i'm tring to fetch the records with the below query i'm getting null response
User.find({ loc:{ $near:{ $geometry: {type: "Point" , coordinates:[77.6974,12.9591] }, $maxDistance:10000 }}}).exec();
Any help would be greatly appreciated. Thanks in advance!
Create index for latlang:
db.<schema>.createIndex({"latlang":"2dsphere"});
then make a query like
User.find({
latlang: {
$near: {
$geometry: {
type: "Point",
coordinates: coords
},
$maxDistance: 10000
}
}
})
Hope this helps!

Get lat and lng using $near and $geometry not working on Mongo + meteor

I am trying to get the all docs that is within 200m from a center point but i am having this error
Exception from sub getLocNearMe id hg3jRDv8onsZEGvBM Error: Exception
while polling query
{"collectionName":"Col_Location","selector":{"loc":{"$near":{"$geometry":{"type":"Point","coordinates":[1.3852457,103.88112509999999]},"$maxDistance":200}}},"options":{"transform":null}}:
$near requires a point, given { type: "Point", coordinates: [
1.3852457, 103.8811251 ] }
client/component/map.jsx
navigator.geolocation.getCurrentPosition(function (pos) {
const sub = Meteor.subscribe("getLocNearMe", pos.coords.latitude, pos.coords.longitude)
Tracker.autorun(function () {
if (sub.ready()) {
Data.MarkersRawData = Col_Location.find().fetch()
}
})
})
lib/collections.jsx
Meteor.publish("getLocNearMe", function(lng, lat) {
check(lat, Number)
check(lng, Number)
const data = Col_Location.find({
loc: {
$near: {
$geometry: {
type: "Point" ,
coordinates: [lng, lat]
},
$maxDistance: 200
}
}
})
console.log(data)
if (data) {
return data
}
return this.ready()
})
server/server.jsx
Col_AllQuestion._ensureIndex({"loc": "2dsphere"})
Col_Location.insert({
loc: {
type: "Point",
coordinates: [103.8, 1.31]
}
})
Testing you "Point" with http://geojsonlint.com/ gives several problems. It seems the (somewhat nitpicky) spec demands your keys to be quoted strings (which i think meteor handles for you) but also the fact that your coordinates are flipped (lat/long).
Putting you sample in like this gives a valid GeoJSON result:
{
"type": "Point",
"coordinates": [ 103.8811251, 1.3852457 ]
}

Sails.js $near query does not work and asks for indices

I'm trying to query the nearest points to some coordinate in Sails.js using MongoDB, but I'm getting the following error:
{ [MongoError: can't find any special indices: 2d (needs index), 2dsphere (needs index), for: { $near: { $geometry: { type: "Point", coordinates: [ "4.3795912", "51.9985675" ] }, $maxDistance: 1000 } }] name: 'MongoError' }
I made sure I had this in bootstrap.js:
sails.models.location.native(function (err, collection) {
collection.ensureIndex({ coordinates: '2dsphere' }, function () {
cb();
});
});
And my Location model looks like this:
attributes: {
coordinates: {
type: 'json'
},
user: {
model: 'user'
}
}
My controller code is the following:
Location.native(function(err, collection) {
var query = {};
collection.find(
query.coordinates = {
$near: {
$geometry: {
type: "Point",
coordinates: [
user.locations[0].lng,
user.locations[0].lat
]
},
$maxDistance : 1000
}
}
).toArray(function(err, result){
if(err) {
console.log(err);
}
else
return res.json(result);
});
});
I'm pretty sure I did just what I was supposed to do, but apparently I have done something wrong or I forgot something. Anyone any idea how to get this to work? Thanks.
I have solved the problem. There were two things I did wrong. First of all, every time I called sails lift the index I created would get removed and I did not know that. Second problem was that my location point was not in proper GeoJSON format:
{
"type": "Point",
"coordinates": [
4.373654,
51.998715
]
}