在猫鼬中创建和查找地理位置

Posted

技术标签:

【中文标题】在猫鼬中创建和查找地理位置【英文标题】:Create & Find GeoLocation in mongoose 【发布时间】:2015-11-18 21:37:44 【问题描述】:

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

这是我模型的一部分:

loc: 
        //type: 'Point', // see 1
        //type: String, // see 2
        coordinates: [Number],
        index: '2dsphere' // see 3
    ,

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

TypeError: Undefined type `Point` at `loc`
  Did you try nesting Schemas? You can only nest using refs or arrays.

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

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

name: 'ValidationError',
  errors: 
    loc: 
       [CastError: Cast to String failed for value "[object Object]" at path "loc"]

@3:如果我想创建这样的索引,我会收到错误:

TypeError: Undefined type `2dsphere` at `loc.index`
  Did you try nesting Schemas? You can only nest using refs or arrays.

所以我尝试将索引存储到对我来说更合适的位置,如下所示:

userSchema.index('loc': '2dsphere');

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

-  [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 ] 

当我将数据库上的模型更新为 $geoNear 命令时,我像这样更新了我的用户:

loc: coordinates: [-73.97, 40.77]

并且可以像这样成功查询它:

 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":  

(我使用了 db.command,因为从我读到的 $geoNear 在使用 find() 时不可用)

到目前为止,我所做的一切都没有成功,所以我现在的问题是:

我的猫鼬模型应该是什么样子? 如何在我的数据库中存储用户及其位置

任何帮助将不胜感激!

【问题讨论】:

【参考方案1】:

这对我来说是点和多边形的更好解决方案。

var WeSchema = new Schema(
Location: 
    type: 
      type: String,
      enum: ['Point', 'Polygon']
    ,
    coordinates: [Number] 
  
);
WeSchema.index(Location: '2dsphere' );

【讨论】:

【参考方案2】:

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

var userSchema = new Schema(
    loc: 
        type:  type: String ,
        coordinates: [Number],
    
);

这确保不会与架构定义的“类型”关键字混淆。如果你真的想支持所有的 GeoJSON 类型,那么你可以稍微宽松一点:

var userSchema = new Schema(
    loc: 
        type:  type: String ,
        coordinates: []
    
);

接下来你想将索引绑定到 shema:

userSchema.index( "loc": "2dsphere" );

然后当然定义一个模型并正确存储东西:

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

 var user = new User( 
     "loc":  
         "type": "Point",
         "coordinates": [-73.97, 40.77]
     
 );

请注意,您的数据必须按照 GeoJSON 和所有 MongoDB 地理空间查询表单支持的 longitude 然后 latitude 顺序。

接下来,与其直接在原始驱动程序方法上深入研究数据库命令的晦涩用法,不如使用直接支持的东西,这样会更好。如$geoNear.aggregate()方法:

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

    
)

现在因为数据是 GeoJSON,距离已经转换成米,所以不需要做其他转换工作。

另请注意,您一直在搞砸这个,除非您删除集合,否则您尝试过的任何索引仍然存在,这可能会导致问题。

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

db.users.dropIndexes();

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

db.users.drop();

正确设置,您不会有任何问题。

【讨论】:

感谢您的帮助!用户的存储现在可以正常工作。我还会看看你的 aggregate 实现,看起来比我以前的那种 hack 好得多 感谢您提供此信息,请在您的地理查询中使用 "spherical" 而不是 "sperical" @ColoGhidini 你能解释一下吗:(为什么聚合更好)“Next, rather than dig into obscure usages of database commands directly on the raw driver method, use things instead that are directly supported, and better 这个方法已经不行了。即使将索引添加到架构中,它也会返回以下错误:$geoNear requires a 2d or 2dsphere index。

以上是关于在猫鼬中创建和查找地理位置的主要内容,如果未能解决你的问题,请参考以下文章

如何使用各种参数在猫鼬中进行搜索查询?

Nest.js - 在猫鼬模式中创建索引

我应该在哪里在猫鼬中创建索引

如果不存在但不更新,如何在猫鼬中创建

如果不存在但不更新,如何在猫鼬中创建

使用种子字符串在猫鼬中创建 ObjectId