使用mongoose的MongoDB没有特殊索引

时间:2014-07-01 21:26:25

标签: node.js mongodb mongoose geospatial

尝试使用GeoJson和$ near让玩家靠近用户使用位置,但是我没有从mongo获得索引设置错误,使用坐标设置为索引的mongoose。对于我见过的所有例子,代码看起来都是正确的。

我想要多个位置字段,所以使用$ near而不是GeoNear。

我从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 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;
    });

};

2 个答案:

答案 0 :(得分:0)

这里的问题是您的索引是在错误的字段上定义的。你在这里真正做的是在"坐标"上定义索引。字段:

var geoSchema = {
  "type": {
    "type": String,
    "enum": ["Point","LineString", "Polygon"],
    "default": "Point"
  },
  "coordinates": {
    "type": Schema.Types.Mixed,
    "index": "2dsphere",
    "default": [0,0]
  }
};

你真正要做的是在"位置"上定义领域。这似乎很难做到" path"定义,但您也可以在"架构"上定义索引。所以作为一个最小的工作示例:

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();
        }
      );
    }
  ]
);

然后查询就可以了。

答案 1 :(得分:0)

"位置"对我来说不起作用,但是当我把它改成" loc"。

时它就起作用了