This question already has answers here:
Find a Location within a stored Circle
(2 answers)
Ambiguity about $geoNear in aggregate query
(1 answer)
Closed 3 years ago.
Currenty I'm working with MongoDB and I have a users collection with the following schema:
const DEFAULT_JOB_RADIUS = 5000 // In meters
const settingsSchema = new Schema({
jobRadius: {
type: Number,
default: DEFAULT_JOB_RADIUS
}
})
const userSchema = new Schema({
firstName: {
trim: true,
type: String
},
lastName: {
trim: true,
type: String
},
email: {
trim: true,
type: String,
unique: true
},
password: {
type: String
},
token: {
type: String
},
fcmToken: {
type: String
},
lastLocation: {
type: pointSchema
},
settings: {
type: settingsSchema,
default: settingsSchema
}
}, {
timestamps: true
})
Point schema looks like this:
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const pointSchema = new Schema({
type: {
type: String,
enum: ['Point'],
default: 'Point'
},
coordinates: {
type: [Number],
default: [0, 0],
index: '2dsphere'
}
});
module.exports = pointSchema
Every user has a jobRadius property. This property represents the max distance of the user to any point.
In my code, I need to fetch all the users that are near a specific point.
Here is what I'm currently trying to do:
async getNearbyUsers(point) {
const users = await this.model.aggregate([
{
$geoNear: {
near: point,
distanceField: "dist.calculated",
maxDistance: '$settings.jobRadius',
spherical: true
}
}
])
return users
}
This code doesn't work. It always bring me all the users inside the collection.
If I change the maxDistance field to something like that, it works:
maxDistance: 1
My questions is - How can I perform such aggregation, where the max distance is dynamic and specific to each user?
Ok so I managed to solve this, with the help of #Ashh
I first calculate the distance between the users and the point and then I filter all the users that their radius property exceeds the distance.
async getNearbyUsers(point) {
const users = await this.model.aggregate([
{
$geoNear: {
near: point,
distanceField: "dist.calculated",
spherical: true
}
},
{
$match: {
$expr: {
$gt: ['$settings.jobRadius', '$dist.calculated']
}
}
}
])
return users
}
Related
good work.
I have a mongoose schema similar to the following
const mongoose = require('mongoose')
var stations = new mongoose.Schema({
//başlık
title: {
type: String
},
//tam adresi
address: {
default:"-",
type: String
},
//ücretlendirme bilgisi
tariff_information: {
default:"-",
type: String
},
//soketler
sockets: {
type: Array,
default:[]
},
//şarj türü (SADECE AC VEYA DC)
type: {
type: String
},
//istasyon sahibi
station_owner: {
type: String
},
//istayon benzersiz kodu
station_code: {
default:"-",
type: String
},
//gps koordinatı
loc: {
"type": {
type: String,
enum: ['Point'],
default: 'Point',
},
"coordinates": {
type: [Number],
default: [0, 0], //[LONG , LAT]
required:true
},
},
}, { timestamps:true, skipVersioning: { dontVersionMe: true } })
stations.index({loc:"2dsphere"})
module.exports = mongoose.model("stations", stations, "stations");
I want to get the data by grouping from here, for example, if there are 1000 locations in 10 km2 area, I want it to return only 1 of them to me.
The reason why I want this is that I have close to 10 million documents in my collection and I'm trying to show it on a map, but it doesn't work at all. Let me reply with a minimum distance of 10km between the locations I want.
I tried using $geoHaystack but it is deprecated. I tried with $geoNear and still couldn't get the result I wanted.
I have restaurant geocoordinates stored in a MongoDB database.
Now I need to create a loop to get all the restaurant geocoordinates with user geocoordinates to get the nearest 5 restaurants. I don't know how to loop and match the geocoordinates with the user.
I want to get exactly 5 restaurants nearby me because the Google place API is integrated in the frontend so I can only get the geocoordinates on which I need to match to get the exact restaurant nearby me.
nearby_restro: (req, res) => {var user_id = req.user;var reqdata = req.body;var lat = reqdata.lat;
var long = reqdata.long;
locationModel.find({
"loc": {$near: [longitude = long, latitude = lat]}}, (err, data) => {console.log(err)
console.log(data)})
model
userId :{ type: mongoose.Schema.Types.ObjectId, required: true, auto: true},
loc: {
type: {
type: String, // Don't do `{ location: { type: String } }`
enum: ['Point'], // 'location.type' must be 'Point'
},
cordinates:[{
longitude:{type:String },
latitude:{type:String },
}],
I want all the nearby restaurants of the user by using coordinates of the restro and the user in long and lat. I am using the user coordinates but this query is not working for me.
MongoDB Geospatial uses geoJSON. below is how the schema should look. note that the geo field was indexed using 2dsphere.
const productSchema = new Schema({
name: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
geo: {
type: {
type: String, // Don't do `{ location: { type: String } }`
enum: ['Point'], // 'location.type' must be 'Point'
default: 'Point',
},
coordinates: [
{ type: Number },
],
},
}, { timestamps: true });
productSchema.index({ geo: '2dsphere', name: 'text' });
to query the product collection, we'll use the MongoDB $geoNear query
const products = ProductModel.aggregate([
{
$geoNear: {
near: { type: 'Point', coordinates: [<lat>, <lng>] },
key: 'geo',
distanceField: 'dist.calculated',
spherical: true,
},
},
{ $limit: 10 },
]);
The distanceField will return a number showing the distance between the item and the passed coordiante.
I have this document in mongo atlas
_id: 5f8939cbedf74e363c37dd86,
firstname: "Person",
lastname: "Person lastname",
sex: "Masculino",
age: "20",
birthDay: 2020-10-07T00:00:00.000+00:00,
vaccines: Array
0:Object
dose: Array
_id: 5f8939cbedf74e363c37dd87
vaccine:5f7023ad96f7ed21e85be521
createdAt:2020-10-16T06:12:27.726+00:00
updatedAt:2020-10-16T06:12:27.726+00:00
1:Object
dose:Array
_id:5f893a9ca98e97188c93fea8
vaccine:5f70259796f7ed21e85be523
2:Object
dose:Array
_id:5f893acda98e97188c93fea9
vaccine:5f7023ad96f7ed21e85be521
This is my mongoose schema
const mySchema = new Schema({
firstname: {
type: String,
required: true,
},
lastname: {
type: String,
required: true,
},
sex: {
type: String,
required: true,
},
age: {
type: String,
required: true,
},
birthDay: {
type: Date,
required: true,
},
vaccines: [
{
type: new Schema(
{
vaccine: {
type: Schema.ObjectId,
ref: "Vaccine",
},
dose: Array,
},
{ timestamps: true }
),
},
],
});
every time I add a new person the vaccines array gets one new object with the timestamp as you can see, in my js file I use this code:
const addPerson = (person) => {
const myPerson= new Model(person);
return myPerson.save();
};
Then when I add a new vaccine for the same person this does not get the timestamp, I'm using this code for that:
const addPersonVaccine = async ({ params, body }) => {
if (!params) return Promise.reject("Invalid ID");
const vaccines = [body];
const foundPerson = await Model.updateOne(
{
_id: params,
},
{
$push: {
vaccines: vaccines,
},
}
);
return foundPerson;
};
This is what my body inside vaccines array has:
[ { vaccine: '5f72c909594ee82d107bf870', dose: 'Primera' } ]
The problem is that I have no results about the next timestamps, as you can see in my mongo atlas document:
1:Object
dose:Array
_id:5f893a9ca98e97188c93fea8
vaccine:5f70259796f7ed21e85be523
2:Object
dose:Array
_id:5f893acda98e97188c93fea9
vaccine:5f7023ad96f7ed21e85be521
Is that the best way to implement timestamps in subdocuments or sub schemas?
I will appreciate your answers, thnks 👏
You can use mongoose schema timestamps options to the inner schemas
const mongoose = require("mongoose");
const forumSchema = new mongoose.Schema(
{
title: { type: String, required: true },
biddings: [
{
type: new mongoose.Schema(
{
biddingId: String,
biddingPoints: Number
},
{ timestamps: true }
)
}
]
},
{ timestamps: true }
);
const Forum = mongoose.model("Forum", forumSchema);
module.exports = Forum;
for more Mongoose schema set timestamp on nested document
I am sending the object to create a user model.
"{
type: 'Point',
coordinates: [ 25.2239771, 51.4993224 ]
}"
And, here is the Mongoose Schema that I created.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UserProfileSchema = new Schema(
{
userId: {
type: String,
// required: true,
unique: true,
},
userFirstName: {
type: String,
// required: true,
},
userLastName: {
type: String,
// required: true,
},
userGender: {
type: String,
// required: true,
},
userCoordinates: {
type: {
type: String,
default: 'Point',
},
coordinates: {
type: [Number],
index: '2dsphere',
},
},
},
{ collection: 'userprofilemodels' }
);
module.exports = UserProfile = mongoose.model(
'userprofilemodels',
UserProfileSchema
);
This is the code that I am using to add geoJson type file. However, I am getting an error.
I also tried to add index after the Schema has been defined
await new userProfileModel({
userId,
userFirstName,
userLastName,
userCoordinates,
})
.save()
.then(() => {
console.log('it worked!');
res.send('worked!');
})
.catch((error) => {
console.log('did not worl')
// console.log(error);
});
If I exclude userCoordinates, then it works. So, def my geoJson object is wrong. However, I have no clue where I have made mistakes.
Mongoose supports GeoJSON objects indexing so first add the "2dsphere" index to the userCoordintes rather than to the coordinates within the object in order to make it work.
userCoordinates: {
type: {
type: String,
default: 'Point',
},
coordinates: {
type: [Number],
default: undefined,
required: true
},
index: '2dsphere'
},
Make sure your userCoordinates looks something like this:
const userCoordinates = {
type: "Point",
coordinates: [coordinatesA, coordinatesB],
};
Taken from the mongoose documentation it seems the GeoJSON Type mustn't be only a String.
here is the example with location as a GeoJSON type:
const citySchema = new mongoose.Schema({
name: String,
location: {
type: {
type: String, // Don't do `{ location: { type: String } }`
enum: ['Point'], // 'location.type' must be 'Point'
required: true
},
coordinates: {
type: [Number],
required: true
}
}
});
I have a model in mongoose
'use strict';
var mongoose = require('bluebird').promisifyAll(require('mongoose'));
var Schema = mongoose.Schema;
function toLower (v) {
return v.toLowerCase();
}
var Signup = new Schema({
name: { type: String, required: true },
email: { type: String, unique: true, required: true, set: toLower },
position: { type: String },
area: String,
companySize: Number,
created: { type: Date, default: Date.now }
});
module.exports = mongoose.model('Signup', Signup);
I would like to group by created (date formatted to day) and count the number of _ids.
I'm new to mongoose and bluebird... Could anyone provide me with an example? Thx!!!
I managed to get exactly what I wanted:
SignupModel
.aggregate([
{
$group: {
_id: { $week: "$created" },
"count": { "$sum": 1 }
}
}
])
.execAsync()
.then(responseWithResult(res))
.catch(handleError(res));
=> Groups by created (week) and sums them