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
}
}
]);
Related
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.
I am creating a store manager app. Here user should be able to query the products using the products query. The condition is those products should be ordered by the distance to products store.
Eg: If the user is searching for a pencil then It should return all the products named pencil which belong to stores within 15 KM, and results should be ordered by the distance to the store.
// The Product Model
const productSchema = new mongoose.Schema({
name: {
type: String,
trim: true,
required: 'Product name is required'
},
store: {
type: mongoose.Schema.ObjectId,
ref: 'Store',
required: 'Store must be connected to the user'
}
});
// The store model
const storeSchema = new mongoose.Schema({
name: {
type: String,
trim: true,
required: 'Please enter a store name'
},
location: {
type: {
type: String,
default: 'Point'
},
coordinates: [{
type: Number,
required: 'You must supply coordinates!'
}]
},
});
this is how I querying products
const products = await Product.find({
name : args.name
store:{
near: { type: "Point", coordinates: [ 79.8612, 6.9271] },
maxDistance: store.maxDistance,
spherical: true
}
});
Unfortunately, It gives me the error
CastError: Cast to ObjectId failed for value "{
near: { type: 'Point', coordinates: [ 79.8612, 6.9271 ] },
maxDistance: 15,
spherical: true
}
I believe I have created indexes correctly
storeSchema.index({
location: '2dsphere'
});
Hi I have User Schema like this:-
var userSchema = new Schema({
name: {type: String, default: null},
location: {
type: { type: String },
coordinates: [Number],
},
sentFriendRequests: [
{type: Schema.Types.ObjectId, ref: 'user'}],
receivedFriendRequests: [
{type: Schema.Types.ObjectId, ref: 'user'}]
});
It is working good for all the requirements. I am searching nearby users with this query:-
User.aggregate(
[{
$geoNear: {
near: { type: "Point", coordinates: [ longitude , latitude ] },
distanceField: "dist.calculated",
num: 5,
spherical: true
}
}], function(err, nearByUsers){
console.log(nearByUsers);
})
The above query is working very good But now i want to search only the users who are not my in my friends array and not in both sent and received friend request array.
Well assuming you have the user document (because you're using its coordinates) then just add a $match to filter out the users before the $geonear phase.
{
$match: {
$and: [
{ _id: {$nin: user.sentFriendRequests},
{ _id: {$nin: user.receivedFriendRequests}
]
}
}
I'm using 3.6.5(mongodb) and trying to get documents near specified location like [-10, 20]...
When I tried get request "http://localhost:3030/ninjas?lng=-80&lat=20" it returns "unable to find index for $geoNear query"
I tried adding index(), changing query and searching official document but, failed.
please help!
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
app.use(bodyParser.json());
mongoose.connect("mongodb://localhost/gpsTest")
.then(() => console.log('Connected to MongoDB...'))
.catch(err => console.error(('Could not connect to MongoDB...\n'), err))
const NinjaSchema = new Schema({
name: {
type: String,
},
rank: {
type: String,
},
available: {
type: Boolean,
default: false
},
geometry: {
type: {
type: String,
default: "Point",
index: '2dsphere'
},
coordinates: {
type: [Number]
}
}
})
NinjaSchema.index({geometry: '2dsphere'});
const Ninja = mongoose.model('ninja', NinjaSchema);
app.post('/ninjas', (req, res) => {
Ninja.create(req.body).then(ninja => {
res.send(ninja);
})
})
app.get('/ninjas', (req, res) => {
Ninja.find({}).where('location').nearSphere({center: {
type: 'Point',
coordinates : [parseFloat(req.query.lng), parseFloat(req.query.lat)],
spherical: true
}}
).then(ninjas => {
res.send(ninjas);
});
})
app.listen(3030, () => {
console.log(`listening port: 3030`);
})
This one is for post request.
{ "name": "test", "rank": "red belt", "available": true,
"geometry" : {"type": "Point", "coordinates": [-80, 27]} }
This is because of typo...
Should change
Ninja.find({}).where('location').nearSphere({center: {...
to
Ninja.find({}).where('geometry').nearSphere({center: {...
I'm trying to get a Mongoose scheme to perform point based $near finds. I'm just trying to obtain random documents and I'm getting guide from this answer.
I've tried:
Video.where('randomTag').near({
center: {
type: 'Point',
coordinates: [-98.18, 19]
}
}).exec(function (err, videos) {
console.log(err)
response.json(videos);
})
Also:
Video.near('randomTag',{
center: {
type: 'Point',
coordinates: [-98.18, 19]
}
}).exec(function (err, videos) {
console.log(err)
response.json(videos);
})
And:
Video.find({
randomTag: {
$near: {
$geometry: {
type: "Point",
coordinates: [Math.random()/Math.random(), 0]
}
}
}
}).exec(function (err,videos) {
response.json(videos)
})
And for all those attemps I got this error:
error: Can't use $near with Number.
I already got the required index:
{randomTag: '2dsphere'}
The schema looks like:
{
videoId: String,
randomTab: Array(Number),
title: String,
playCount: Number
}
Here is some sample data.
{
"videoId": "aRDAz55d-y",
"randomTag": [2.255285185646381,0],
"title": "La décima, inolvidable",
"playCount": 254111
}
{
"videoId": "vAFj32af",
"randomTag": [0.4515513067517708,0],
"title": "SILePetitPrince",
"playCount": 900
}
This is whole error trace:
Error: Can't use $near with Number.
at SchemaNumber.castForQuery (/storage/home/dev/final-cut/node_modules/mongoose/lib/schema/number.js:261:13)
at module.exports (/storage/home/dev/final-cut/node_modules/mongoose/lib/cast.js:196:39)
at Query.cast (/storage/home/dev/final-cut/node_modules/mongoose/lib/query.js:2341:10)
at Query.find (/storage/home/dev/final-cut/node_modules/mongoose/lib/query.js:998:10)
at Function.find (/storage/home/dev/final-cut/node_modules/mongoose/lib/model.js:1026:13)
at sayHello (/storage/home/dev/final-cut/api/controllers/api.js:23:15)
at Layer.handle [as handle_request] (/storage/home/dev/final-cut/node_modules/express/lib/router/layer.js:95:5)
at next (/storage/home/dev/final-cut/node_modules/express/lib/router/route.js:131:13)
at Route.dispatch (/storage/home/dev/final-cut/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/storage/home/dev/final-cut/node_modules/express/lib/router/layer.js:95:5)
at /storage/home/dev/final-cut/node_modules/express/lib/router/index.js:277:22
at Function.process_params (/storage/home/dev/final-cut/node_modules/express/lib/router/index.js:330:12)
at next (/storage/home/dev/final-cut/node_modules/express/lib/router/index.js:271:10)
at Function.handle (/storage/home/dev/final-cut/node_modules/express/lib/router/index.js:176:3)
at router (/storage/home/dev/final-cut/node_modules/express/lib/router/index.js:46:12)
at Layer.handle [as handle_request] (/storage/home/dev/final-cut/node_modules/express/lib/router/layer.js:95:5)
GET /api/hello 500 20.560 ms - -
The reason of the Math.random() use is because of the randomness need. Is there something I'm missing?
Looks good to me. You must be doing something different to this listing:
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
var videoSchema = new Schema({
videoId: String,
randomTag: [Number],
title: String,
playCount: Number
});
videoSchema.index({ "randomTag": "2dsphere" });
var Video = mongoose.model( 'Video', videoSchema );
mongoose.connect('mongodb://localhost/test');
mongoose.set("debug",true);
Video.find(
{
"randomTag": {
"$near": {
"$geometry": {
"type": "Point",
"coordinates": [Math.random()/Math.random(),0]
}
}
}
},
function(err,videos) {
if (err) throw err;
console.log(videos);
mongoose.disconnect();
}
);
Which gives me results like this:
Mongoose: videos.ensureIndex({ randomTag: '2dsphere' }) { background: true }
Mongoose: videos.find({ randomTag: { '$near': { '$geometry': { type: 'Point', coordinates: [ 1.8434117849022023, '\u001b[33m0\u001b[39m' ] } } } }) { fields: undefined }
[ { playCount: 254111,
title: 'La décima, inolvidable',
randomTag: [ 2.255285185646381, 0 ],
videoId: 'aRDAz55d-y',
_id: 5627616d76dfa5adcd39fd38 },
{ playCount: 900,
title: 'SILePetitPrince',
randomTag: [ 0.4515513067517708, 0 ],
videoId: 'vAFj32af',
_id: 5627616d76dfa5adcd39fd39 } ]