geospatial queries on subdocuments - node.js

I have a mongoose schema with subdocuments that contain a location field (with 2dSpehre index). Like this:
var playerSchema = new mongoose.Schema({
name: { type: String, required: true },
addresses: [
{
address: {
street: String,
city: String,
zip: String,
country: String
},
loc: { type: [Number], index: '2dSphere' }
}
],
});
When I try to query for addresses via geospatial operators I get this error: planner returned error: unable to find index for $geoNear query. The query looks like this:
var query = {
'addresses.loc': {
$nearSphere: {
$geometry: { type: 'Point', coordinates: [16.3738189, 48.2081743] }
}
}
};
Player.find(query).exec();
I also checked via mongo that the index really exists:
> db.player.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "project.player"
},
{
"v" : 1,
"key" : {
"addresses.loc" : "2dsphere"
},
"name" : "addresses.loc_2dsphere",
"ns" : "project.player",
"2dsphereIndexVersion" : 2
}
]
What am I doing wrong? Thanks in advance.

Are you sure you are using the right collection? Mongoose will pluralize your collection name by default (so players instead of player).
The script below is working for me. For some reason Mongoose wasn't creating the 2dsphere index for me when it was specified in the schema so I moved that out.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var playerSchema = new mongoose.Schema({
name: { type: String, required: true },
addresses: [
{
address: {
street: String,
city: String,
zip: String,
country: String
},
loc: { 'type': { type: String }, 'coordinates': { type: [Number] } }
}
],
});
playerSchema.index({'addresses.loc': '2dsphere'});
var Player = mongoose.model('Player', playerSchema);
mongoose.connect('mongodb://localhost/test');
var query = Player.find({
'addresses.loc': {
$nearSphere: {
$geometry: { type: 'Point', coordinates: [16.3738189, 48.2081743] }
}
}
}, function (err, players) {
console.log(err)
console.log(players)
});

Related

Mongoose match regex on subdocuments array

Is it possible to use $match inside an aggregate on a subdocument array ?
Here's what I have:
mainModel.js
const mainModelSchema = mongoose.Schema({
name: {
type: String,
required: [true, 'mainModel name required']
},
arr: {
type: [subModel.schema],
default: []
},
});
const mainModel = mongoose.model('mainModel', mainModelSchema);
subModel.js
const subModelSchema = mongoose.Schema({
a: {
type: String,
required: [true, 'subModel a required']
},
});
const subModel = mongoose.model('subModel', subModelSchema);
My first aggregate request (this is working fine) :
mongoose.model('mainModel').aggregate([
{
$match: {
{ name: { '$regex': '.*someValue.*', '$options': 'i' } },
}
}
])
My second aggregate request (this is not working) :
mongoose.model('mainModel').aggregate([
{
$match: {
{ 'arr.a': { '$regex': '.*someValue.*', '$options': 'i' } },
}
}
])
I'd like to be able to filter documents using a regex on a field located inside a subdocument array.

Can't use $near with String error in node express

I am getting error "Can't use $near with String error in node express" when we find records basis on longitude and latitude with maxDistance.
following is code, I am using:-
1-schema code:-
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var dtSchema = new Schema({
name:String,
date: {type: Date, default: Date.now},
location: { type: String, coordinates: [Number] },
category:String
});
//dtSchema.index({location: '2dsphere'});
module.exports = mongoose.model('places', dtSchema);
2-server.js code for fetch records
app.get('/location/:lon/:lat', function(req, res) {
console.log(req.params.lon);
console.log(req.params.lat);
location.find({location:
{ $near:
{
$geometry: { type: "Point", coordinates: [req.params.lon, req.params.lat ] },
$maxDistance: 5000
}
}}, function(err, places) {
if(!err){
res.send('({"records":' + JSON.stringify(places) + '});');
}
else{
console.log(err);
res.send("error coming")
}
});
});
parameter sending URL
http://localhost:4700/location/-73.9667/40.78
when we execute code and hit above URL. I found error "Can't use $near with String error in node express"
I had the same problem a while ago. The error is in the schema declaration.
var dtSchema = new Schema({
name:String,
date: {type: Date, default: Date.now},
location: {
type: {
type: String
},
coordinates: [Number]
},
category:String
});
db.location.aggregate([ { "$geoNear": { "near": { "type": "Point", "coordinates": [72.4468035,23.032069] }, "maxDistance": 500, "spherical": true, "distanceField": "distance" } } ])
The schema for geoNear should be
loc: {
type: {
type: String,
enum: ["Point"],
},
coordinates: {
type: [Number],
index: "2dsphere",
// 2dSphere supports queries that calculate geometries on an
// earth like sphere
},
},

how to use Mongoose to (add to , update,delete) Nested documents

I am a fresh mongoose user and I have a small exercise I have this schema
`var BusinessSchema = mongoose.Schema({
personal_email: { type: String, required: true, unique: true },
business_name: { type: String, required: true, unique: true },
business_emails: [{ email: String, Description: String }],
business_logo: { data: Buffer, contentType: String },
//Business Services
services: [{
service_name: { type:String,required:true},
service_price: Number,
promotion_offer : Number,
service_rating : [{Clinet_username:String ,rating : Number}],
service_reviews : [{Clinet_username:String ,review : String}],
type_flag : Boolean,
available_flag : Boolean
}]
});`
what I want to do is to update or add new service or delete rating using mongoose
business.update({// something here to update service_rating },function(err,found_business)
{
}); business.update({// something here to add new service_rating },function(err,found_business)
{
}); business.update({// something here to delete service_rating },function(err,found_business)
{
});
var where_clause = { /* your where clause */ };
var service_rating = {"username", 5};
to add :
business.update(where_clause, {
'$addToSet' : {
services.service_rating : service_rating
}
}, callback);
to delete :
business.update(where_clause, {
'$pull' : {
services.service_rating : service_rating
}
}, callback);
to update :
var other_where = {services.service_rating : {"user", 5}}; // your where clause
business.update(other_where, {
'$set': {
'services.service_rating.Clinet_username' : 'newUser',
'services.service_rating.rating' : 10
}
}, callback);

Mongoose populate() returns empty array with no errors

I've been trying to get this populate thing to work, but I'm getting issues because I am not getting the expected results, and no errors to work with. Just simply an empty array.
My models look like this. Each their own file
var mongoose = require( 'mongoose' );
var upgradeSchema = new mongoose.Schema({
type: {
type: String,
default: "Any"
},
ability: String,
ability_desc: String,
level: Number,
tag: String
});
mongoose.model('Upgrade', upgradeSchema);
and the other
var mongoose = require( 'mongoose' );
var crypto = require('crypto');
var jwt = require('jsonwebtoken');
var userSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true
},
hero: {
level: Number,
name: String,
type: {
path: String,
heroType: String
},
upgrades: [{
type: mongoose.Schema.Types.ObjectId, ref: 'Upgrade'
}],
unspent_xp: Number,
total_xp: Number,
},
armyTotal: {
type: Number,
default: 0,
max: 5000
},
army:[{
foc_slot: String,
unit_name: String,
unit_cost: Number
}],
username: {
type: String,
required: true,
unique: true,
},
faction: String,
name: {
type: String,
required: true
},
hash: String,
salt: String,
roles: {
type: String,
default: 'player' }
});
And I'm trying to do this
module.exports.profileRead = function(req, res) {
User
.findById(req.payload._id)
.populate('hero.upgrades')
.exec(function (err, user) {
if (err){
console.log(err);
} else {
res.status(200).json(user);
console.log("success");
}
});
}
};
This is an example of a user
{
"_id" : ObjectId("57b4b56ea03757e12c94826e"),
"hash" : "76",
"salt" : "2",
"hero" : {
"upgrades" : [
"57b42773f7cac42a21fb03f9"
],
"total_xp" : 0,
"unspent_xp" : 0,
"type" : {
"heroType" : "Psyker",
"path" : ""
},
"name" : "Jon Doe"
},
"username" : "michaelzmyers",
"faction" : "Grey Knights",
"email" : "email#gmail.com",
"name" : "Michael Myers",
"roles" : "player",
"army" : [],
"armyTotal" : 625,
"__v" : 3
}
Now, I've tried an array of just the strings with ObjectId's in them, similar to the eample, and I've also tried using ObjectId("STRINGHERE") and no luck. They both return just an empty array. However, if i get rid of the populate call (or change the contents inside populate from hero.upgrades to just hero, or upgrades) then it just returns an array of strings. I feel like the problem is with populate and how I'm using it. HOWEVER, when I had just a single upgrade in my databse (the test upgrade), everything worked fine. Now nothing works. Any thoughts? I'd be happy to provide more code if needed.
I found that during my little research that it will work:
User
.findById(req.payload._id)
.populate({
path: 'hero.upgrades',
model: 'Upgrade'
})
.exec(function (err, user) {
if (err){
console.log(err);
} else {
res.status(200).json(user);
console.log("success");
}
});
}
It looks like when user is giving nested object notation i.e. hero.upgrades into populate method, Mongoose got problems with detecting referring model.

MongoDB GeoJSON weird query results

I am using GeoJSON to store coordinates of locations that i want later on to query by proximity,
my schema looks like the following:
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var BranchSchema = new Schema({
parentId: {
type: Schema.Types.ObjectId,
required: 'The ID of the restaurant is required.',
index: true
},
name: {
type: 'String',
required: 'The name is required.'
},
loc: {
'type': {
type: 'String',
default: 'Point'
},
coordinates: {
type: [Number],
default: [0,0]
}
}
});
BranchSchema.index({loc: "2dsphere"});
module.exports = mongoose.model('Branch', BranchSchema);
I am using mongoose and my query looks something like the following:
Branch.where('loc').near({
center: [long, lat],
maxDistance: proximity,
spherical: true
}).exec(function (err, branches) {
if (err) {
return res.status(400)
.send({
message: errors.getErrorMessage(err)
});
}
return res.json(branches);
});
i added a new branch to the database with the following coordinates Latitude:34.237918
Longitude:36.002197
and i query the database with the following coordinates:
Latitude:33.882957
Longitude:35.502319
and a maxDistance of 100
the difference between these 2 coordinates is more than 100m however the database return results, what am i missing???
Can you double check that you're doing the query that you think you are doing? Your query works fine for me:
> db.test.drop()
> var p = { "type" : "Point", "coordinates" : [36.002197, 34.237918] }
> var q = { "type" : "Point", "coordinates" : [35.502319, 33.882957] }
> db.test.insert({ "loc" : p })
> db.test.ensureIndex({ "loc" : "2dsphere" })
> db.test.count({
"loc" : {
"$near" : {
"$geometry" : q,
"$maxDistance" : 100
}
}
})
0

Resources