Node.js 近地层猫鼬聚集

Node.js 近地层猫鼬聚集,node.js,mongodb,mongoose,geospatial,aggregation-framework,Node.js,Mongodb,Mongoose,Geospatial,Aggregation Framework,我正在尝试使用mongoosegeonear命令实现分页。geoNear似乎不支持skip,而且我知道聚合将起作用(使用分页时需要付出性能代价)。如何将此查询转换为聚合查询以跳过多个文档 exports.near = function(req, res) { if(req.query.lat && req.query.lng) { var point = { type: "Point", coordinates : [Number(

我正在尝试使用mongoosegeonear命令实现分页。geoNear似乎不支持skip,而且我知道聚合将起作用(使用分页时需要付出性能代价)。如何将此查询转换为聚合查询以跳过多个文档

exports.near = function(req, res) {
    if(req.query.lat && req.query.lng) {
        var point = {
            type: "Point", coordinates : [Number(req.query.lng), Number(req.query.lat)]
        };
        var queryParams = {
            spherical: true,
            skip: 0,
            limit: 10,
            distanceMultiplier: 6371 // radians to kilometers. (The radius of the Earth is approximately 3,959 miles or 6,371 kilometers.)
        };
        if(req.query.q) {
            var matcher = new RegExp(req.query.q, "i");
            queryParams.query = {
                $or: [
                    {'name': matcher },
                    {'address.full': matcher}
                ]
            };
        }
        if(req.query.limit) {
            queryParams.limit = parseInt(req.query.limit, 10);
        }
        if(req.query.offset) {
            queryParams.skip = parseInt(req.query.offset, 10);
        }
        Venue.geoNear(point, queryParams, function(error, results, stats) {
            // TODO
        });
    }
};

您可以使用聚合框架来实现这一点,因为操作本质上是相同的,因此没有实际的惩罚

但是,尽管mongoose
.find()
方法目前存在与运算符等价的问题,但您始终可以获取原始节点驱动程序连接对象并执行查询

如果您准备实现一点处理,您甚至不需要扔掉“人口”之类的东西

这是我的测试数据:

{ 
    "_id" : "P1",
    "amenity" : "restaurant", 
    "shape" : { 
        "type" : "Point", 
        "coordinates" : [ 2, 2 ] 
    }
}
{ 
    "_id" : "P3",
    "amenity" : "police",
    "shape" : { 
        "type" : "Point", 
        "coordinates" : [ 4, 2 ]
    }
}
{ 
    "_id" : "P4",
    "amenity" : "police",
    "shape" : {
        "type" : "Point",
        "coordinates" : [ 4, 4 ]
    }
}
{ 
    "_id" : "P2",
    "amenity" : "restaurant",
    "shape" : { 
        "type" : "Point",
        "coordinates" : [ 2, 4 ]
    }, 
    "info" : ObjectId("539b90543249ff8d18e863fb")
}
以及处理此问题的基本代码:

var mongoose = require('mongoose'),
    async = require('async'),
    Schema = mongoose.Schema;


mongoose.connect('mongodb://localhost');

var infoSchema = new Schema({
  "description": String
});

var shapeSchema = new Schema({
  "_id": String,
  "amenity": String,
  "shape": {
    "type": { "type": String },
    "coordinates": []
  },
  "info": { "type": Schema.Types.ObjectId, "ref": "Info" }
});

var Shape = mongoose.model( "Shape", shapeSchema );
var Info = mongoose.model( "Info", infoSchema );


Shape.collection.find(
  {
    "shape": {
      "$nearSphere": {
        "$geometry": {
          "type": "Point",
          "coordinates": [ 2, 4 ]
        }
      }
    }
  },
  {
    "skip": 0, "limit": 2
  },
  function(err,cursor) {

    cursor.toArray(function(err,shapes) {

      Shape.populate( shapes, { path: "info" }, function(err,docs) {
        if (err) throw err;

        console.log( JSON.stringify( docs, undefined, 4 ) );
      });

    });

  }
);
因此,您在游标上使用了跳过限制操作,返回了游标,甚至将文档处理回“Mongoose documents”,这样您就可以对它们调用
.populate()
之类的函数

不过,我预计目前的问题会很快得到解决

或者使用聚合:

Shape.aggregate(
  [
    { "$geoNear": {
        "near": {
          "type": "Point",
          "coordinates": [ 2, 4 ]
        },
        "spherical": true,
        "distanceField": "dis"
    }},
    { "$skip": 0 },
    { "$limit": 2 }

  ],
  function(err,shapes) {
    if (err) throw err;
    //console.log( shapes );

    shapes = shapes.map(function(x) {
      delete x.dis;
      return new Shape( x );
    });

    Shape.populate( shapes, { path: "info" }, function(err,docs) {
      if (err) throw err;

      console.log( JSON.stringify( docs, undefined, 4 ) );
    });

  }
);
您可以在其中执行相同的操作,例如使用
.populate()
。这两种情况都会返回这样的结果,并匹配“填充”字段:

{
    "_id": "P2",
    "amenity": "restaurant",
    "info": {
        "_id": "539b90543249ff8d18e863fb",
        "description": "Jamies Restaurant",
        "__v": 0
    },
    "shape": {
        "type": "Point",
        "coordinates": [
            2,
            4
        ]
    }
},
{
    "info": null,
    "_id": "P4",
    "amenity": "police",
    "shape": {
        "type": "Point",
        "coordinates": [
            4,
            4
        ]
    }
}

当然,如果您不需要球形几何体计算,那么操作符在Mongoose实现的
.find()

中工作得非常好。您可以使用聚合框架来实现这一点,并且没有实际的惩罚,因为操作本质上是相同的

但是,尽管mongoose
.find()
方法目前存在与运算符等价的问题,但您始终可以获取原始节点驱动程序连接对象并执行查询

如果您准备实现一点处理,您甚至不需要扔掉“人口”之类的东西

这是我的测试数据:

{ 
    "_id" : "P1",
    "amenity" : "restaurant", 
    "shape" : { 
        "type" : "Point", 
        "coordinates" : [ 2, 2 ] 
    }
}
{ 
    "_id" : "P3",
    "amenity" : "police",
    "shape" : { 
        "type" : "Point", 
        "coordinates" : [ 4, 2 ]
    }
}
{ 
    "_id" : "P4",
    "amenity" : "police",
    "shape" : {
        "type" : "Point",
        "coordinates" : [ 4, 4 ]
    }
}
{ 
    "_id" : "P2",
    "amenity" : "restaurant",
    "shape" : { 
        "type" : "Point",
        "coordinates" : [ 2, 4 ]
    }, 
    "info" : ObjectId("539b90543249ff8d18e863fb")
}
以及处理此问题的基本代码:

var mongoose = require('mongoose'),
    async = require('async'),
    Schema = mongoose.Schema;


mongoose.connect('mongodb://localhost');

var infoSchema = new Schema({
  "description": String
});

var shapeSchema = new Schema({
  "_id": String,
  "amenity": String,
  "shape": {
    "type": { "type": String },
    "coordinates": []
  },
  "info": { "type": Schema.Types.ObjectId, "ref": "Info" }
});

var Shape = mongoose.model( "Shape", shapeSchema );
var Info = mongoose.model( "Info", infoSchema );


Shape.collection.find(
  {
    "shape": {
      "$nearSphere": {
        "$geometry": {
          "type": "Point",
          "coordinates": [ 2, 4 ]
        }
      }
    }
  },
  {
    "skip": 0, "limit": 2
  },
  function(err,cursor) {

    cursor.toArray(function(err,shapes) {

      Shape.populate( shapes, { path: "info" }, function(err,docs) {
        if (err) throw err;

        console.log( JSON.stringify( docs, undefined, 4 ) );
      });

    });

  }
);
因此,您在游标上使用了跳过限制操作,返回了游标,甚至将文档处理回“Mongoose documents”,这样您就可以对它们调用
.populate()
之类的函数

不过,我预计目前的问题会很快得到解决

或者使用聚合:

Shape.aggregate(
  [
    { "$geoNear": {
        "near": {
          "type": "Point",
          "coordinates": [ 2, 4 ]
        },
        "spherical": true,
        "distanceField": "dis"
    }},
    { "$skip": 0 },
    { "$limit": 2 }

  ],
  function(err,shapes) {
    if (err) throw err;
    //console.log( shapes );

    shapes = shapes.map(function(x) {
      delete x.dis;
      return new Shape( x );
    });

    Shape.populate( shapes, { path: "info" }, function(err,docs) {
      if (err) throw err;

      console.log( JSON.stringify( docs, undefined, 4 ) );
    });

  }
);
您可以在其中执行相同的操作,例如使用
.populate()
。这两种情况都会返回这样的结果,并匹配“填充”字段:

{
    "_id": "P2",
    "amenity": "restaurant",
    "info": {
        "_id": "539b90543249ff8d18e863fb",
        "description": "Jamies Restaurant",
        "__v": 0
    },
    "shape": {
        "type": "Point",
        "coordinates": [
            2,
            4
        ]
    }
},
{
    "info": null,
    "_id": "P4",
    "amenity": "police",
    "shape": {
        "type": "Point",
        "coordinates": [
            4,
            4
        ]
    }
}

当然,如果您不需要球形几何体计算,那么操作符在Mongoose实现的
.find()

中工作得非常好。谢谢Neil,我已经更新了我的代码以使用您的聚合示例:这解决了我的分页问题。但是计算的距离已经改变了,你知道为什么会这样吗?另外,我所说的性能成本是这样的:您认为这种分页方式会有相同的性能损失吗?@strada不太确定您所说的距离更改是什么意思,甚至不确定在除了选择和分页之外没有其他操作执行的情况下,为什么需要使用聚合命令。您可以通过标准查询来实现这一点。也许通过“距离”,您没有考虑聚合方法发出RAIDAN。分页性能始终与实际执行的“页面深度”有关。跳过的成本通常可以通过“范围查询”来降低,或者通过“黑名单”来降低,正如上面提到的帖子中基本上指出的那样。如何使用find query获得距离?谢谢Neil,我已经更新了我的代码以使用您的聚合示例:这解决了我的分页问题。但是计算的距离已经改变了,你知道为什么会这样吗?另外,我所说的性能成本是这样的:您认为这种分页方式会有相同的性能损失吗?@strada不太确定您所说的距离更改是什么意思,甚至不确定在除了选择和分页之外没有其他操作执行的情况下,为什么需要使用聚合命令。您可以通过标准查询来实现这一点。也许通过“距离”,您没有考虑聚合方法发出RAIDAN。分页性能始终与实际执行的“页面深度”有关。跳过的成本通常通过“范围查询”来降低,或者通过“黑名单”来降低,正如上面提到的帖子中基本上指出的那样。如何通过find query获得距离?