Reputation: 4139
Trying to use GeoJson and $near to get players near user using location, however I get no indexes set error from mongo, using mongoose that has the coordinates set to index. Code looks correct to all examples I have seen.
I want to have multiple locations field too so using $near instead of GeoNear.
Error I'm getting from mongoDB
MongoError: can't find any special indices: 2d (needs index), 2dsphere (needs index), for: { location: { $near: { $geometry: { coordinates: [ 52, -0.4 ], type: "Point" }, $maxDistance: 10 } } }
Player and Users model
/** =========== Player Model =========== **/
var mongoose = require('mongoose');
var _ = require('underscore');
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;
var geoJSONSchema = {
type: {
type: String,
enum: ['Point', 'LineString', 'Polygon'],
default: 'Point'
},
coordinates:{
type: mongoose.Schema.Types.Mixed,
index: '2dsphere',
default: [0,0]
}
};
.../\/\/\... other code .../\/\/\...
var playerSchema = new Schema({
created: { type: Date, default: Date.now },
controller_id: {
type: ObjectId,
required: true
},
controller: {
type: String,
required: true,
enum: ['ai', 'user'],
default: 'ai'
},
state:{
type: String,
required: true,
enum: ['survivor', 'zombie'],
default: 'survivor'
},
timestamps: {
created: { type: Date, default: Date.now },
last_active: { type: Date },
ai_last_spawned_at: { type: Date }
},
stats: playerStatsSchema,
profile: profileSchema,
location: geoJSONSchema,
//locations: geoJSONSchema, // Locations player has been
items: [{ type: Schema.Types.ObjectId, ref: 'items' }]
},{ collection : 'player' });
.../\/\/\... other code .../\/\/\...
playerSchema.pre('init', function (next) {
// do stuff
next();
});
// Compile Model
var Player = mongoose.model('Player', playerSchema);
/** =========== User Controller =========== **/
// Player is created with any new user, called inside another method.
var user = new User({
auth: options.auth,
contact: options.contact
}),
playerLocation = _.extend({ type: 'Point', coordinates: [0,0] }, options.location),
player = new Player({
controller_id: user._id,
controller: 'user',
state: 'survivor',
location: playerLocation,
//locations: playerLocation,
profile: {
name: (options.contact.first_name || '')
}
});
player.save(function (err, playerDoc) {
if (err) {
console.warn('[cUser:player.save]', err);
if (options.error) options.error(err);
return;
}
user.player_id = playerDoc._id;
user.player = playerDoc;
user.save(function (err, userDoc) {
if (err) {
console.error('[cUser:user.save]', err);
return;
}
if (options.success instanceof Function) options.success();
console.info('[cUser:user.save]created a new user (' + options.name + ') and player');
});
});
/** =========== Player GeoNear (User Method) =========== **/
userSchema.methods.getPlayersNear = function(distance){
if(!Player)Player = mongoose.model('Player');
return Player.find({ location: { $near: { $geometry: this.player.location , $maxDistance: distance||100 /* In Meters */ } }}, function(err,docs){
if(err) console.error('[mUser:player]',err);
return docs;
});
};
Upvotes: 2
Views: 752
Reputation: 109
"location" did not work for me, but it worked when I changed it to "loc".
Upvotes: 0
Reputation: 151112
The problem here is that your index is defined on the wrong field. What you actually did here was define the index on the "coordinates" field:
var geoSchema = {
"type": {
"type": String,
"enum": ["Point","LineString", "Polygon"],
"default": "Point"
},
"coordinates": {
"type": Schema.Types.Mixed,
"index": "2dsphere",
"default": [0,0]
}
};
Really what you want to do is define that on the "location" field. That might seem difficult to do by "path" definition, but you can also define indexes on the "schema". So as a minimal working example:
var async = require("async");
mongoose = require("mongoose"),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/geo');
var geoSchema = {
"type": {
"type": String,
"enum": ["Point","LineString", "Polygon"],
"default": "Point"
},
"coordinates": {
"type": Schema.Types.Mixed,
"default": [0,0]
}
};
var playerSchema = new Schema({
"name": String,
"location": geoSchema
});
playerSchema.index({ "location": "2dsphere"});
var Player = mongoose.model("Player", playerSchema, "player");
var player = new Player({
"name": "bill",
"location": {
"type": "Point",
"coordinates": [1,2]
}
});
async.series(
[
function(callback) {
player.save(function(err,player) {
if (err) throw err;
console.log(player);
callback();
});
},
function(callback) {
Player.find(
{
"location": {
"$near": {
"$geometry": {
"type": "Point",
"coordinates": [1,2]
}
}
}
},
function(err,players) {
if (err) throw err;
console.log(players);
callback();
}
);
}
]
);
And then the query works just fine.
Upvotes: 0