Node.js 近地层猫鼬聚集
我正在尝试使用mongoosegeonear命令实现分页。geoNear似乎不支持skip,而且我知道聚合将起作用(使用分页时需要付出性能代价)。如何将此查询转换为聚合查询以跳过多个文档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(
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获得距离?