【问题标题】:Mongodb: Query documents by a sub-document field (GeoJSON)Mongodb:通过子文档字段(GeoJSON)查询文档
【发布时间】:2019-07-11 07:39:54
【问题描述】:

我的数据库模型中有三个文档模式:pointSchema(只是一个 GeoJSON 点定义)、PlaceSchema(这是一个真实的地方,就像一个夜总会)和 EventSchema(这将存储与派对和节日等事件相关的数据)。

但是我遇到了一些问题。我需要根据他的位置查询事件文档,但是,该位置数据存储在与事件有关系的子文档中。

以下是我的架构定义:

const pointSchema = new mongoose.Schema({
  type: {
    type: String,
    enum: ['Point'],
    required: true
  },
  coordinates: {
    type: [Number],
    required: true
  }
});

const PlaceSchema = new mongoose.Schema(
  {
    name: {
      type: String,
      required: true
    },
    location: {
      type: pointSchema,
      required: true
    }
  },
  {
    versionKey: false,
    timestamps: true
  }
);
PlaceSchema.index({
  name: 'text',
  location: "2dsphere"
});

const EventSchema = new mongoose.Schema(
  {
    name: {
      type: String,
      required: true
    },
    place: {
      type: mongoose.SchemaTypes.ObjectId,
      ref: 'Place'
    }
  },
  {
    versionKey: false,
    timestamps: true
  }
)
EventSchema.index({
  name: 'text'
})

我可以使用以下方式过滤 Places 文档:

db.Places.find({ 
    location: {
        $geoWithin: { 
            $centerSphere: [ 
                [ -28.824342, -49.218433 ],
                100 / 6378.1 
            ] 
        } 
    }
})

但是当我尝试过滤事件时,我不能这样做。我已经尝试过这样的查询:

db.Events.find({ 
    "place.location": {
        $geoWithin: { 
            $centerSphere: [ 
                [ -28.824342, -49.218433 ],
                100 / 6378.1 
            ] 
        } 
    }
})

但该解决方案不起作用。有人可以帮助我吗?

谢谢。

【问题讨论】:

  • 您的 location 密钥存在于适当的架构中,您刚刚在事件中引用了它。
  • 你好 Anthony,当然...但是我不能在我的事件过滤器中使用那个键(在嵌套文档中)?
  • 请说明您需要什么?你需要什么输出,因为你在这里走错了方向。您正在尝试使用引用键访问子/父字段。
  • 事件文档中的place 只是一个ObjectId 还是作为子文档添加的地方文档本身?
  • 你好@AbdelrahmanHossam,这个地方只是事件文档中的一个objectId。

标签: mongodb mongoose mongodb-query geojson mongoose-schema


【解决方案1】:

由于您的event 文档中的place 只是一个ObjectId,那么您有两种选择之一

  1. 多次发现
let places = db.Places.find({ 
   location: {
       $geoWithin: { 
           $centerSphere: [ 
               [ -28.824342, -49.218433 ],
               100 / 6378.1 
           ] 
       } 
   }
}, { _id:1 }) // get the places _ids

let events = db.events.find({
   place: { $in: places.map(p => p._id) }
}) // get events that has the places _ids

  1. 聚合
const stages = [
{ $geoNear: {
   near: { type: "Point", coordinates: [ -28.824342, -49.218433 ] },
   distanceField: "distance",
   spherical: true,
   maxDistance: 100 / 6378.1
} },
{ $lookup: {
   from: 'events',
   localField: '_id',
   foreignField: 'place',
   as: 'events'
} }
];

let result = db.places.aggregate(stages);

【讨论】:

  • 您好,谢谢您的回复。我尝试了您的第二个建议,使用聚合。但我面临这个问题:MongoError:geoNear 没有地理索引
  • @RenanCunha 您是否有多个关于地点集合的地理索引?如果是这样,您需要在计算距离时指定要使用的地理空间索引字段。
  • 嗨,在地点集合中,我只有一个索引:PlaceSchema.index({ location: "2dsphere" });
  • 尝试再次检查索引是否实际创建。我已经检查过了,它按预期工作。尝试在 mongo shell 中运行它(使用正确的数据库后)db.places.getIndexes() [ { "v" : 2, "key" : { "id" : 1 }, "name" : "_id ","ns":"test.places"},{"v":2,"key":{"location":"2dsphere"},"name":"location_2dsphere","ns":"test.places ", "2dsphereIndexVersion" : 3 } ]
猜你喜欢
  • 2018-12-14
  • 1970-01-01
  • 2018-12-01
  • 2017-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-23
  • 2021-02-25
相关资源
最近更新 更多