I hope some one can help me - i want to populate a subdocument with a geo query to sort them:
i've got these models (simplified):
(a lot of articles):
var articleSchema = mongoose.Schema({
places: [{ type: mongoose.Schema.Types.ObjectId, ref: "places", required: false }],
someData: { type: String, required: true },
})
(a lot of places):
var placeSchema = mongoose.Schema({
longitudelatitude: {
type: { type: String, required: true },
coordinates: [
{ type: Number, required: true }, //longitude
{ type: Number, required: true } //latitude
]},
someData: { type: String, required: true }
})
my first query to find only places near a Position works fine:
getPlacesNearBy: function (lng, lat, skipNumber, limitNumber, callback) {
Place.find({
longitudelatitude: {
$near: {
$geometry: { type: "Point", coordinates: [lng, lat] },}}
}, null, {skip: skipNumber, limit: limitNumber}, function (err, foundPlaces) {
if (err)
return callback(err, null);
return callback(null, foundPlaces);
})
},
i get places near me - i can choose with limit how many - and i can reload some more with skip
now i wanted to do something similar:
i want to get an article - and populate the stored places (where you can get them) AND AFTER THAT i want to sort the places by distance and maybe to skip or limit the Response
so i tryed:
getPlacesforArticle: function (articleId, lng, lat, skipNumber, limitNumber, callback) {
var projection = null;
Article.findById(articleId, {places: 1}).populate("places", projection, {
longitudelatitude: {
$near: {
$geometry: { type: "Point", coordinates: [lng, lat] },
}
}
}, {skip: skipNumber, limit: limitNumber}).exec(function (getError, foundArticle) {
if (getError)
return callback(getError, null);
callback(null, foundArticle.places);
});
}
},
So this query is working (throw no error) but it doesnt response what i want - i get places but they are "ordered" by database sequenze not by distance - so the $near seems to be ignored (tested without this query brings same result) but when i filter to some other content that works fine (like Name="test") also the limit is working but i cant skip some places of this response...
well i hope some one understand me and can help me =)!
thank you very much!
So i've got a solution for my Problem...
https://docs.mongodb.com/manual/reference/command/geoNear/
use db.aggregate instead of db.find!
there you can define a seperate query =)
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 am trying to use Mongo's GeoSpatial features to locate documents based on coordinates.
I need to create indexes for it to work - but it seems like I can't get the index created? Can you help?
I'll walk through what I have so far.
//User saves the location using a PUT Command.
props.updateBandLocation({
geometry: {
type: "Point",
coordinates: [ lat, lon ]
}
})
Here is the route that puts it in the database. I try to get the index created here.
router.put('/:id', (req, res) => {
quoteGenerator.findByIdAndUpdate({_id: req.params.id}, req.body).then(() => {
quoteGenerator.findOne({_id: req.params.id}).then(generator => res.send(generator))
quoteGenerator.createIndex( { bandLocation: "2dsphere" } )
})
})
The indexing throws an error in my terminal but it creates the location anyways. Here it is in the database.
//How the query looks in the database
"bandLocation": {
"geometry": {
"type": "Point",
"coordinates": [
32.96179,
-96.82916850000001
]
}
},
Lastly, I am trying to get all the documents near a point using this route.
router.get('/allbands/:lat/:lng', (req, res) => {
quoteGenerator.find(
{
bandLocation:
{ $near: {
$geometry: {
type : "Point",
coordinates : [-req.params.lng, +req.params.lat],
}
}
}
}
).then(bands => res.json(bands))
});
Thanks for any help you have to offer!
Here is my schema --
//Create GeoSchema
const GeoSchema = new Schema({
geometry: {
type: {
type: String,
default: "Point",
index: "2dsphere",
},
coordinates: {
type: [Number],
},
}
})
//Create Schema - Band
const AutoQuoteGeneratorSchema = new Schema({
baseCost: {
type: Number
},
mainDate: {
type: Object
},
quoteGenerator: {
type: Array,
required: true,
},
userId: {
type: String,
required: true,
},
type: {
type: String,
required: true,
},
bandName: {
type: String,
required: true,
},
bandBio: {
type: String,
required: true,
},
bandLocation: GeoSchema,
bandTour: {
type: Array,
required: true,
},
bandGenre: {
type: String,
required: true,
},
youtube: {
type: Array,
required: true,
},
published: {
type: Boolean,
required: true,
},
posts: {
type: Array,
required: true,
},
});
Ok so from what i can see we have a couple of problems:
Structure:
From the 2dsphere index docs:
The 2dsphere index supports data stored as GeoJSON objects and legacy coordinate pairs
What type are GeoJSON objects?, they're { type: <GeoJSON type> , coordinates: <coordinates> }
And what type are legacy coordinates pairs? they're in the form of: [<longitude>, <latitude> ] or { <field1>: <x>, <field2>: <y> }
So we can see bandLocation is neither, you need to use
quoteGenerator.createIndex( { "bandLocation.geometry": "2dsphere" } )
Your Coordinates are in the wrong order, You need to specify in the order of longitude then latitude. The valid range of latitude in degrees is -90 and +90. Your value of latitude of -96 is out of range.
So change your document to [-96.82916850000001, 32.96179].
Now we just need to adjust your query:
quoteGenerator.find({
"bandLocation.geometry":
{ $near: {
$geometry: {
type : "Point",
coordinates : [-req.params.lng, +req.params.lat],
}
}
}
})
** Another thing that pops up is that you create (try to create) an index every time there's a function call when in-fact you should only do it once. it should not be a part of your code. Now this won't throw an error but it's redundant as Mongo auto index documents on changes / inserts.
I know several question have been asked in here but no one give me the correct answer. So basically I have Schema like here
const cashFlowSchema = new Schema({
date: { type: Date, default: Date.now },
type: { type: String, required: true },
category: { type: String, required: true },
amount: { type: Number, required: true },
description: String
});
And then I tried to create get sum for amount with aggregate like this
CashFlow.aggregate([{
$group: {
_id: null,
balance: { $sum: "$amount" }
}
}], function(err, result) {
if (err) {
console.log(err);
return;
}
console.log(result);
});
And give the result like this
[ { _id: null, balance: 0 } ]
But if I try in Robo3T (previously Robomongo), it give me correct answer. I use mongodb version 3.4. Thank you before.
Update
I found the answer, so it's my silly mistake. After I enable debug mode in mongoose, it show I'm make wrong connection to the collection. After fix it, I get the correct result. I will delete this question soon, thank's all before.
This is my mongoose activity schema.
var Activity = new Schema({
activityName: {
type: String,
required: true
},
activityPlace: {
name: {
type: String,
default: 'Virtual'
},
location: {
type: {
type: String,
default: 'Point'
},
coordinates: {
type: Array,
default: [0, 0]
}
},
},
activityCategory: {
type: String,
required: true
},
createdBy: {
type: Schema.ObjectId,
ref: 'User'
},
usersAttending: [{
type: Schema.ObjectId,
ref: 'User'
}],
});
It has a field 'usersAttending'.
this is my function where i calling this mongo activity model.
var getActivityNearbyFeed = function (location, distance, id, page, pagesize, callback) {
var criteria = {
"createdBy": {
$ne: id
},
"activityPlace.location.coordinates": {
$geoWithin: {
$centerSphere: [
location.coordinates,
distance
]
}
},
};
var projection = {};
var option = {
lean: true
}
var query = Models.Activity.find(criteria, projection, option);
query.skip(page * pagesize);
query.limit(pagesize);
//query.sort();
query.exec(function (err, data) {
if (err) {
callback(err);
} else {
callback(null, data);
}
})
};
I want to get the data sorted on the basis of the length of the array usersAttending. i am getting the data in the query object, is there any way through which i can get data inside in that object sorted on the basis of length of usersAttending array. i have used the sort function but unable to find correct syntax for it. thanks in advance.
Unfortunately you can't do that directly. The simplest answer would be to maintain a length variable that you use to keep track of the array length, incrementing it every time the insertion is done in the array and decrementing for deletion.
Another way of doing it is by using the .aggregate() method as described at How to sort documents based on length of an Array field. Though for your query it would be quite complex to write indeed.