Node.js Mongoose MongoDB地理空间查询

Node.js Mongoose MongoDB地理空间查询,node.js,mongodb,mongoose,mongodb-query,aggregation-framework,Node.js,Mongodb,Mongoose,Mongodb Query,Aggregation Framework,我有一个项目集合,可以容纳数千到几十万个文档。在该集合上,我希望执行地理空间查询。使用Mongoose,有两个选项-find()和聚合管道。我已经在下面展示了我的两个实现: 猫鼬模型 首先,以下是我的猫鼬模型的相关属性: // Define the schema const itemSchema = new mongoose.Schema({ // Firebase UID (in addition to the Mongo ObjectID) owner: {

我有一个
项目
集合,可以容纳数千到几十万个文档。在该集合上,我希望执行地理空间查询。使用Mongoose,有两个选项-
find()
和聚合管道。我已经在下面展示了我的两个实现:

猫鼬模型 首先,以下是我的猫鼬模型的相关属性:

// Define the schema
const itemSchema = new mongoose.Schema({
    // Firebase UID (in addition to the Mongo ObjectID)
    owner: {
        type: String,
        required: true,
        ref: 'User'
    },
    // ... Some more fields
    numberOfViews: {
        type: Number,
        required: true,
        default: 0
    },
    numberOfLikes: {
        type: Number,
        required: true, 
        default: 0
    },
    location: {
        type: {
            type: 'String',
            default: 'Point',
            required: true
        },
        coordinates: {
            type: [Number],
            required: true,
        },
    }
}, {
    timestamps: true
});

// 2dsphere index
itemSchema.index({ "location": "2dsphere" });

// Create the model
const Item = mongoose.model('Item', itemSchema);
查找查询 聚合管道 假设需要计算的距离:

// These variables are populated based on URL Query Parameters.
const query = {};
const sort = {};

const geoSpatialQuery = {
    $geoNear: {
        near: { 
            type: 'Point', 
            coordinates: [parseInt(req.query.lng), parseInt(req.query.lat)] 
        },
        distanceField: "distance",
        maxDistance: parseInt(req.query.maxDistance),
        query,
        spherical: true
    }
};

const items = await Item.aggregate([
    geoSpatialQuery,
    { $limit: parseInt(req.query.limit) },
    { $skip: parseInt(req.query.skip) },
    { $sort: { distance: -1, ...sort } } 
]).exec();

res.send(items);
编辑-示例文件已修改 下面是一个文档的示例,其中包含
集合中的所有属性:

{
   "_id":"5cd08927c19d1dd118d39a2b",
   "imagePaths":{
      "standard":{
         "images":[
            "users/zbYmcwsGhcU3LwROLWa4eC0RRgG3/5cd08927c19d1dd118d39a2b/images/Image-aafe69c7-f93e-411e-b75d-319042068921-standard.jpg",
            "users/zbYmcwsGhcU3LwROLWa4eC0RRgG3/5cd08927c19d1dd118d39a2b/images/Image-397c95c6-fb10-4005-b511-692f991341fb-standard.jpg",
            "users/zbYmcwsGhcU3LwROLWa4eC0RRgG3/5cd08927c19d1dd118d39a2b/images/Image-e54db72e-7613-433d-8d9b-8d2347440204-standard.jpg",
            "users/zbYmcwsGhcU3LwROLWa4eC0RRgG3/5cd08927c19d1dd118d39a2b/images/Image-c767f54f-7d1e-4737-b0e7-c02ee5d8f1cf-standard.jpg"
         ],
         "profile":"users/zbYmcwsGhcU3LwROLWa4eC0RRgG3/5cd08927c19d1dd118d39a2b/images/Image-51318c32-38dc-44ac-aac3-c8cc46698cfa-standard-profile.jpg"
      },
      "thumbnail":"users/zbYmcwsGhcU3LwROLWa4eC0RRgG3/5cd08927c19d1dd118d39a2b/images/Image-51318c32-38dc-44ac-aac3-c8cc46698cfa-thumbnail.jpg",
      "medium":"users/zbYmcwsGhcU3LwROLWa4eC0RRgG3/5cd08927c19d1dd118d39a2b/images/Image-51318c32-38dc-44ac-aac3-c8cc46698cfa-medium.jpg"
   },
   "location":{
      "type":"Point",
      "coordinates":[
         -110.8571443,
         35.4586858
      ]
   },
   "numberOfViews":0,
   "numberOfLikes":0,
   "monetarySellingAmount":9000,
   "exchangeCategories":[
      "Math"
    ],
   "itemCategories":[
      "Sports"
   ],
   "title":"My title",
   "itemDescription":"A description",
   "exchangeRadius":10,
   "owner":"zbYmcwsGhcU3LwROLWa4eC0RRgG3",
   "reports":[],
   "createdAt":"2019-05-06T19:21:13.217Z",
   "updatedAt":"2019-05-06T19:21:13.217Z",
   "__v":0
}
问题 基于以上,我想问几个问题

  • 我对普通Mongoose查询的实现和对聚合管道的使用之间是否存在性能差异

  • 如果说
    near
    geoNear
    与使用GeoJSON的
    2dsphere
    索引时与
    nearSphere
    非常相似,除了
    geoNear
    提供额外数据和默认限制之外,这是正确的吗?也就是说,尽管具有不同的单位,但从概念上讲,这两个查询都将显示某个位置特定半径内的相关数据,尽管事实上该字段被称为
    radius
    ,用于
    nearSphere
    maxDistance
    near

  • 在上面的示例中,如何减轻使用
    skip
    的性能损失,但仍然能够在查询和聚合中实现分页

  • find()
    函数允许一个可选参数来确定将返回哪些字段。聚合管道需要一个
    $project
    阶段来执行相同的操作。在管道中使用
    $project
    以优化速度/效率时,是否有特定的顺序,还是无关紧要


  • 我希望根据堆栈溢出规则允许这种类型的问题。谢谢。

    我用2dsphere索引尝试了下面的查询。我使用了聚合管道
    对于下面的查询

    db.items.createIndex({location:"2dsphere"})
    
    在使用聚合管道时,它为您提供了更大的结果集灵活性。此外,聚合管道将提高运行地理相关搜索的性能

    db.items.aggregate([
    {
     $geoNear: {
        near: { type: "Point", coordinates: [ -110.8571443 , 35.4586858 ] },
        key: "location",
        distanceField: "dist.calculated",
        minDistance: 2, 
        query: { "itemDescription": "A description" }
     }])
    
    关于您的$skip问题,下面的问题将让您对$skip操作有更多的了解


    您可以根据需要使用$project。在我们的例子中,使用$project超过1000万的数据时,我们没有太多的性能问题

    我尝试了以下使用2dsphere索引的查询。我使用了聚合管道
    对于下面的查询

    db.items.createIndex({location:"2dsphere"})
    
    在使用聚合管道时,它为您提供了更大的结果集灵活性。此外,聚合管道将提高运行地理相关搜索的性能

    db.items.aggregate([
    {
     $geoNear: {
        near: { type: "Point", coordinates: [ -110.8571443 , 35.4586858 ] },
        key: "location",
        distanceField: "dist.calculated",
        minDistance: 2, 
        query: { "itemDescription": "A description" }
     }])
    
    关于您的$skip问题,下面的问题将让您对$skip操作有更多的了解


    您可以根据需要使用$project。在我们的案例中,我们使用$project时没有太多性能问题超过1000万的数据

    请分享您收集的样本文档。聚合管道是一种数据流,因此数据通过管道进行过滤,因此它取决于您的要求。@SheshanGamage谢谢您的评论。请查看更新/编辑以查看示例文档的内容。请共享您收藏的示例文档。聚合管道是一种数据流,因此数据通过管道进行过滤,因此它取决于您的要求。@SheshanGamage谢谢您的评论。请参阅更新/编辑以查看示例文档的内容。谢谢。什么是
    key
    ,根据您链接的答案,在
    limit
    之前使用
    sort
    是否更好?key是您的“位置”字段名:{“类型”:“点”,“坐标”:[-110.8571443,35.4586858]}是的,在管道末端使用limit总是很好的谢谢。什么是
    key
    ,根据您链接的答案,在
    limit
    之前使用
    sort
    是否更好?key是您的“位置”字段名:{“类型”:“点”,“坐标”:[-110.8571443,35.4586858]}是的,在管道末端使用限值总是好的