Using geoJSON in mongoose schema and use it in a query - node.js

I'm new to mongoDB and the usage of geoJSON within it.
I have the following schema I created using the mongoose module:
var mongoose = require('mongoose');
var hikeSchema = mongoose.Schema({
name: String,
area: String,
length: Number,
time: String,
Difficulty: { type : Number, min : 0 , max :5 },
start_coord: {
lon: Number,
lat: Number
},
rank_count: Number,
avg_overall_rating: { type : Number, min : 0 , max :5 },
completed_count: Number,
description: String,
ranking_pages: [
mongoose.Schema.Types.ObjectId
]
});
module.exports = mongoose.model('Hike', hikeSchema);
I used a simple Number type to represent to longitude and latitude inside a sub object within the schema.
I don't know if this is the way to go about it. I want it to be saved as a geoJSON object and then run queries on this object.

I recommand you to see the mongoDB part for geolocation datas : http://docs.mongodb.org/manual/core/2d/
To store longitude, latitude, MongoDB take you the correct data structure to save items :
To store location data as legacy coordinate pairs, use an array or an embedded document.
When possible, use the array format:
loc : [ < longitude > , < latitude > ]
Consider the embedded document form:
loc : { lng : , lat : }
Arrays are preferred as certain languages do not guarantee associative map ordering.
For all points, if you use longitude and latitude, store coordinates in longitude, latitude order.
On your shema, change
start_coord: {
lon: Number,
lat: Number
},
By :
start_coord: {
lng: Number,
lat: Number
},
Then you should add a 2dindex for your field start_coords to use all mongoDB geospatial queries :
db.collection.ensureIndex( { start_coord : "2d" } , { min : <l ower bound > , max : < upper bound > } )
EDIT It's important to set min and max if your longitude and latitude is not a real lng/lat (for example if you could use 2dindexes in a orthonormal map)
Now you can use all geospatial query operators : http://docs.mongodb.org/manual/reference/operator/query-geospatial/

You can also do it this way:
start_coord: {
type: [Number], // [<longitude>, <latitude>]
index: '2d' // create the geospatial index
}
Check this tutorial: How to use geospatial indexing in mongoDb

Related

List locations near by to a lat, lon point from stored lat, lon in database

I have [lat, lon] pairs of different locations stored in MongoDb. Now I want to compare a certain coordinates pair by distance like in circle of 2 km from that point and want to take results of all from database.
You should have a look at geoNear command.
Generic example is the following:
db.runCommand(
{
geoNear: "places", // Your target collection
near: { type: "Point", coordinates: [ -73.9667, 40.78 ] }, // Point coordinates
spherical: true, // 2dsphere index required for using this option
query: { yourField: "someFilterVale" }, // Additional regular filtering
maxDistance: 2000 // Maximum distance in meters/radians
}
)
minDistance is also available for querying
For this purpose you should have 2d or 2dsphere index in your collection.
Also there is a $geoNear aggregation.

Change order of parameters in mongoose

I have following structure in my model :
geoLocation: {
latitude: {
type: Number
},
longitude: {
type: Number
}
}
I want to change the order to :
geoLocation: {
longitude: {
type: Number
},
latitude: {
type: Number
}
}
The problem is I have existing database in which data has been stored as :
"geoLocation" : {
"latitude" : 23.0720184,
"longitude" : 72.54213399999999
}
And I want to change order and want to save them as :
"geoLocation" : {
"longitude" : 72.54213399999999,
"latitude" : 23.0720184
}
I am using $centerSphere query of mongodb and it requires longitude as first argument. I tried to change order in model but it is not affecting the database.
How can I do that?
There is one way of doing it is by using aggregation. Please look for other better options too.
Using $project and $out we can simply put the longitude at first, the mongodb code snippet is shown below
db.collection_name.aggregate([{
$project:{
_id:1,
"project all other fields as shown for _id":1,
// Changing part
"geoLocation.longitude":"$geoLocation.longitude",
"geoLocation.latitude":"geoLocation.latitude"
}},
// Overwriting the same collection with latitude and longitude changed
{$out: "collection_name"}]);

Mongoose find all documents where array.length is greater than 0 & sort the data

I am using mongoose to perform CRUD operation on MongoDB. This is how my schema looks.
var EmployeeSchema = new Schema({
name: String,
description: {
type: String,
default: 'No description'
},
departments: []
});
Each employee can belong to multiple department. Departments array will look like [1,2,3]. In this case departments.length = 3. If the employee does not belong to any department, the departments.length will be equal to 0.
I need to find all employee where EmployeeSchema.departments.length > 0 & if query return more than 10 records, I need to get only employees having maximum no of departments.
Is it possible to use Mongoose.find() to get the desired result?
Presuming your model is called Employee:
Employee.find({ "departments.0": { "$exists": true } },function(err,docs) {
})
As $exists asks for the 0 index of an array which means it has something in it.
The same applies to a maximum number:
Employee.find({ "departments.9": { "$exists": true } },function(err,docs) {
})
So that needs to have at least 10 entries in the array to match.
Really though you should record the length of the array and update with $inc every time something is added. Then you can do:
Employee.find({ "departmentsLength": { "$gt": 0 } },function(err,docs) {
})
On the "departmentsLength" property you store. That property can be indexed, which makes it much more efficient.
By some reason, selected answer doesn't work as for now. There is the $size operator.
Usage:
collection.find({ field: { $size: 1 } });
Will look for arrays with length 1.
use can using $where like this:
await EmployeeSchema.find( {$where:'this.departments.length>0'} )
If anyone is looking for array length is greater than 1, you can do like below,
db.collection.find({ "arrayField.1" : { $exists: true }})
The above query will check if the array field has value at the first index, it means it has more than 1 items in the array. Note: Array index start from 0.

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..

Mongodb geospatial query for searching lat, long within a radius

I am trying to get the results based on geospatial query of mongodb within a circle of 5 km radius of a given lat,long.
For that i am using this query
{coords :
{ $nearSphere :{
$geometry: {
type : "Point",
coordinates : [ data.longitude, data.latitude]
},
$maxDistance: 5000
}
}
}
But it is giving me undefined output. But when i remove the $maxDistance it is giving me all the results. I want to get the results only under the specified maxDistance.

Resources