MongoDB/Mongoose - 与 geoNear 和子文档的聚合
Posted
技术标签:
【中文标题】MongoDB/Mongoose - 与 geoNear 和子文档的聚合【英文标题】:MongoDB/Mongoose - Aggregation with geoNear & subdocuments 【发布时间】:2015-05-29 10:39:22 【问题描述】:我正在使用node-geoip 模块并执行聚合查询。我正在执行查询的架构如下所示:
var mongoose = require('mongoose');
require('./location.js');
module.exports = mongoose.model('Region',
attr1: Number,
attr2: String,
attr3: String,
locations:[mongoose.model('Location').schema]
);
和
var mongoose = require('mongoose');
module.exports = mongoose.model('Location',
attr1: Number,
latlong: type: [Number], index: '2d' ,
);
我需要在聚合查询中执行 $geoNear 操作,但遇到了一些问题。首先,这是我的聚合方法:
var region = require('../models/region');
var geo = geoip.lookup(req.ip);
region.aggregate([
$unwind: "$locations",
$project:
attr1 : 1,
attr2 : 1,
locations : 1,
lower : "$cond" : [$lt: [ '$locations.attr1', '$attr1'], 1, 0]
,
$geoNear:
near: type:"Point", '$locations.latlong': geo.ll ,
maxDistance: 40000,
distanceField: "dist.calculated"
,
$sort: 'locations.attr1': -1 ,
$match : lower : 1,
$limit: 1
], function(err,f)...);
我遇到的第一个问题是 geoNear 显然必须在管道的第一阶段:exception: $geoNear is only allowed as the first pipeline stage
。所以我的问题是,我可以在子文档中执行 geoNear 搜索而不展开它们吗?如果有,怎么做?
我收到的另一条错误消息是errmsg: \"exception: 'near' field must be point\"
。这是什么意思,它对我的代码意味着什么?我尝试使用near
作为:
near: type:"Point", '$locations.latlong': geo.ll ,
【问题讨论】:
您是否尝试将“附近”定义为一个点?例如;附近:[经度,纬度], 数组上的索引是多键的。$geoNear
应该在数组上正常工作 - 排序应该是每个文档中最近的点。第二个错误表明您没有使用正确语法的$geoNear
。查看$geoNear
,尤其是底部的示例。
@wdberkeley 感谢您的回复。当您说“应按每个文档中最近的点进行排序”时,您是什么意思?我真的不明白这对我的代码意味着什么?这是否意味着我可以在展开$locations
之前将$geoNear
移动到第一阶段?
@wdberkeley 另外,我的语法怎么错了?我看过这些例子并遵循了他们的惯例。具体有什么问题?
【参考方案1】:
首先声明:我不是 Node/Mongoose 专家,所以我希望您能将通用格式翻译成 Node/Mongoose。
对于错误:
errmsg: "exception: 'near' field must be point"
对于 '2d' 索引,这不能是 GeoJson 点,而需要是“旧坐标对”。例如,
"$geoNear":
"near": geo.ll,
"maxDistance": 40000,
"distanceField": "dist.calculated"
如果您想使用 GeoJSON,您需要使用“2dsphere”索引。
通过该更改,$geoNear 查询将与查询中的点数组一起使用。 shell中的一个例子:
> db.test.createIndex( "locations": "2d" )
> db.test.insert( "locations": [ [1, 2], [10, 20] ] );
> db.test.insert( "locations": [ [100, 100], [180, 180] ] );
> db.test.aggregate([
"$geoNear":
"near": [10, 10],
"maxDistance": 40000,
"distanceField": "dist.calculated",
num: 1
]);
"result": [
"_id": ObjectId("552aaf7478dd9c25a3472a2a"),
"locations": [
[
1,
2
],
[
10,
20
]
],
"dist":
"calculated": 10
],
"ok": 1
请注意,每个文档(最近点)只能得到一个距离,这在语义上与展开然后确定到每个点的距离不同。我不确定这对您的用例是否重要。
【讨论】:
以上是关于MongoDB/Mongoose - 与 geoNear 和子文档的聚合的主要内容,如果未能解决你的问题,请参考以下文章
将 apollo 服务器与 mongodb mongoose 连接
使用聚合 mongodb mongoose 将集合子子文档与其他集合子文档连接起来
MongoDB/Mongoose - 仅当某个字段是唯一的时才将对象添加到对象数组中