我试图在我的用户模型中保存一个位置的经度/纬度,并用$geoNear查询它.我已经看过了几乎所有我能找到的关于这个主题的页面,但我仍然不确定如何1)适当地创建模型,以及如何查询它.

以下是我的模型的一部分:

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

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

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

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

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

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()时不可用)

到目前为止,我所做的一切都毫无结果,所以我现在的问题是:

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

任何帮助都将不胜感激!

推荐答案

如果希望模式支持GeoJSON,首先需要正确构造:

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

这确保了不会与模式定义的"type"关键字混淆.如果您真的想支持所有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地理空间查询表单支持的顺序从longitudelatitude排列.

接下来,与其直接在原始驱动程序方法上挖掘数据库命令的模糊用法,不如使用直接支持的更好的方法.例如,.aggregate()方法为$geoNear:

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

    }
)

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

还要注意的是,你一直在胡乱处理这个问题,除非你删除集合,否则你try 的任何索引都将仍然存在,这可能会导致问题.

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

db.users.dropIndexes();

或者,由于您可能需要对数据进行重新塑造,因此请停止收集并重新开始:

db.users.drop();

把事情安排妥当,你就不会有问题了.

Mongodb相关问答推荐

更新查询mongoose 中的礼宾更新字段

我可以在BSON中使用代理字段吗?

在MongoDB Aggregate for My BooksDB中将`$match`放在`$unwin`之前或之后的区别

Select 筛选聚合中的嵌套字段

MongoDB:如何获取多个$indexOfArray值?

如何在 MongoDB 中已经存在的 slug 中添加一个随机数?

使用MongoDB作为我们的主数据库,我应该使用单独的图数据库来实现实体之间的关系吗?

使用绝对类型在 Typescript 中编写 Mongoose 的类型化模型和模式的类和接口

NoSql 参考数据

使用管道聚合的 Spring Data MongoDB 查找

MongoDB中超过2GB的数据库

Mongoose.js:嵌套属性的原子更新?

MongoError:Topology is closed, please connect despite established database connection

mongodb 的计数性能

120 个 mongodb 集合与单个集合 - 哪个更有效?

是否可以使用聚合框架对 MongoDB 中的 2 个字段求和?

用于 MongoDB 的 Node.js 模块

mongoose查询返回 null

如何使用 Spring 的 MongoTemplate 和 Query 类检索字段子集?

Mongodb Compass 无法在 Ubuntu 18.10 中打开