在mongoose中创建和查找GeoLocation

Mar*_*kus 12 geospatial mongoose mongodb node.js mongodb-query

我正在尝试在我的用户模型中保存位置的经度/纬度并使用它进行查询 $geoNear.我已经查看了几乎所有关于该主题的页面,但我仍然不确定如何1)适当地创建模型以及如何查询它.

这是我的模型的一部分:

loc: {
        //type: 'Point', // see 1
        //type: String, // see 2
        coordinates: [Number],
        index: '2dsphere' // see 3
    },
Run Code Online (Sandbox Code Playgroud)

@ 1:根据文档,如果我想存储一个点,那么类型必须是'Point',但它会抛出

TypeError: Undefined type `Point` at `loc`
  Did you try nesting Schemas? You can only nest using refs or arrays.
Run Code Online (Sandbox Code Playgroud)

这是有道理的,因为我猜它应该是一个 String

@ 2:这不会立即引发错误,但是当我尝试存储用户时,我得到:

name: 'ValidationError',
  errors: 
   { loc: 
      { [CastError: Cast to String failed for value "[object Object]" at path "loc"]
Run Code Online (Sandbox Code Playgroud)

@ 3:如果我想创建索引,我会得到错误:

TypeError: Undefined type `2dsphere` at `loc.index`
  Did you try nesting Schemas? You can only nest using refs or arrays.
Run Code Online (Sandbox Code Playgroud)

所以我试着将索引存储到对我来说更合适的东西:

userSchema.index({'loc': '2dsphere'});
Run Code Online (Sandbox Code Playgroud)

当我尝试保存新用户时会抛出以下错误:

- { [MongoError: Can't extract geo keys from object, malformed geometry?:{ coordinates: [ -73.97, 40.77 ] }]
  name: 'MongoError',
  message: 'Can\'t extract geo keys from object, malformed geometry?:{ coordinates: [ -73.97, 40.77 ] }',
  ok: 1,
  n: 0,
  code: 16572,
  errmsg: 'Can\'t extract geo keys from object, malformed geometry?:{ coordinates: [ -73.97, 40.77 ] }',
  writeConcernError: 
   { code: 16572,
     errmsg: 'Can\'t extract geo keys from object, malformed geometry?:{ coordinates: [ -73.97, 40.77 ] }' } }
MongoError: Can't extract geo keys from object, malformed geometry?:{ coordinates: [ -73.97, 40.77 ] }
Run Code Online (Sandbox Code Playgroud)

当我将数据库上的模型更新为a时 $geoNear命令时,我更新了我的用户,如下所示:

loc: {coordinates: [-73.97, 40.77]}
Run Code Online (Sandbox Code Playgroud)

并可以成功查询它:

 mongoose.model('users').db.db.command({
    "geoNear": users,
    "near": [
        <latitude>,
        <longitude>
    ],
    "spherical": true,
    "distanceMultiplier": 6378.1, // multiplier for kilometres
    "maxDistance": 100 / 6378.1, // every user within 100 km
    "query": { }
Run Code Online (Sandbox Code Playgroud)

(我使用db.command,因为我读过的$geoNear内容在使用时不可用find())

到目前为止我尝试过的所有东西都让我无处可去,所以现在我的问题是:

  • 我的猫鼬模型应该怎么样?
  • 如何将用户的位置存储在我的数据库中

任何帮助将非常感激!

Bla*_*ven 50

如果您希望架构支持GeoJSON,那么您首先需要正确构建它:

var userSchema = new Schema({
    loc: {
        type: { type: String },
        coordinates: [Number],
    }
});
Run Code Online (Sandbox Code Playgroud)

这确保了模式定义的"type"关键字没有混淆.如果你真的想要支持所有GeoJSON类型,那么你可以让它更宽松一点:

var userSchema = new Schema({
    loc: {
        type: { type: String },
        coordinates: []
    }
});
Run Code Online (Sandbox Code Playgroud)

接下来,您要将索引绑定到shema:

userSchema.index({ "loc": "2dsphere" });
Run Code Online (Sandbox Code Playgroud)

然后当然定义一个模型并正确存储事物:

var User = mongoose.model( "User", userSchema );

 var user = new User({ 
     "loc": { 
         "type": "Point",
         "coordinates": [-73.97, 40.77]
     }
 });
Run Code Online (Sandbox Code Playgroud)

注意到您的数据必须是经度,然后是GeoJSON和所有MongoDB地理空间查询表单支持的纬度顺序.

接下来,不要直接在原始驱动程序方法上深入挖掘数据库命令的模糊用法,而是使用直接支持的东西,而不是更好.如$geoNear对于.aggregate()方法:

User.aggregate(
    [
        { "$geoNear": {
            "near": {
                "type": "Point",
                "coordinates": [<long>,<lat>]
            },
            "distanceField": "distance",
            "spherical": true,
            "maxDistance": 10000
        }}
    ],
    function(err,results) {

    }
)
Run Code Online (Sandbox Code Playgroud)

现在因为数据是GeoJSON,距离已经转换为米,因此不需要进行其他转换工作.

还要注意的是,你一直在搞乱这个,除非你删除你所尝试的任何索引仍然存在,这可能会导致问题.

您可以轻松地从mongodb shell中的集合中删除所有索引:

db.users.dropIndexes();
Run Code Online (Sandbox Code Playgroud)

或者,因为您可能需要进行一些数据重新整形,然后删除该集合并重新开始:

db.users.drop();
Run Code Online (Sandbox Code Playgroud)

正确设置,你就没有问题.

  • 感谢您提供此信息,请在地理查询中使用"球形"`而不是"sperical". (2认同)