我有一个MongoDB 集合,我的文档具有以下结构
{
...
distanceDeviation: 2.0,
loc: [
[24.77, 67.5],
[24.78, 67.6],
[24.79, 67.7],
[24.80, 67.8],
...
]
...
}
我有集合地理索引(在loc
上使用 ensureIndex )。
我希望有一个查询,如果我发送两个点,Mongo会从集合中返回文档,这两个点都包含loc
中的两个点阵列。
我能够使用带有固定$within
参数的$radius
执行此操作,如下所示:
{
"$and": [
{
"loc": {
"$within": {
"$center": [
[
24.812640000000002,
67.01985
],
1.5
]
}
}
},
{
"loc": {
"$within": {
"$center": [
[
24.900070000000003,
67.16828000000001
],
1.5
]
}
}
}
]
}
但是,如果不是1.5
指定为半径,我想指定使用属性 distanceDeviation ,这是文档的一部分。
无论如何,如果没有$where
,最好能实现这一点。如果不是,那我怎么能用$where
来做。
答案 0 :(得分:0)
使用aggregate()
及其$geoNear
运算符可以完成这项工作,但有点尴尬。尴尬,因为聚合只允许一个$geoNear
,它必须位于聚合pipleline的顶部。所以,我们必须做两个聚合然后合并结果。
想法:$geoNear
将返回给定点与“loc”路线中每个点的距离。然后我们可以采用最小距离,使用$cond
运算符进行测试,是否在distanceDeviation
范围内并返回文档,在这种情况下。
结果是与第一个点匹配的文档数组。然后重复另一个点的操作,然后将两个数组合并到两个数组中出现的文档列表中。
这是它的工作原理(为了更好的可读性,我使用了其他坐标)
db.xx.drop();
db.xx.insert( { distanceDeviation: 2.0, loc: [ [0,0], [10,-10], [20,10], [30,0] ] } );
db.xx.insert( { distanceDeviation: 0.1, loc: [ [0,0], [10,-10], [20,10], [30,0] ] } );
db.xx.ensureIndex({ loc: "2d" });
db.xx.find();
// points to query:
pointA = [1,1]
pointB = [21,11]
aggA = db.xx.aggregate([
{ $geoNear: { near: pointA, distanceField: "dist" } },
{ $group: { _id: { oid: "$_id", dev: "$distanceDeviation" }, min: { $min: "$dist" } } },
{ $project: { oid: "$_id.oid", isNear: { $cond: [ { $lt: [ "$min", "$_id.dev" ] }, 1, 0 ] }, _id: 0 } },
{ $match: { isNear: 1 } },
]);
aggB = db.xx.aggregate([
{ $geoNear: { near: pointB, distanceField: "dist" } },
{ $group: { _id: { oid: "$_id", dev: "$distanceDeviation" }, min: { $min: "$dist" } } },
{ $project: { oid: "$_id.oid", isNear: { $cond: [ { $lt: [ "$min", "$_id.dev" ] }, 1, 0 ] }, _id: 0 } },
{ $match: { isNear: 1 } },
]);
print("\nObjects with point near route:\n");
aggA.result.forEach( function( a ) {
aggB.result.forEach( function( b ) {
if ( a.oid.toString == b.oid.toString ) { print( a.oid ) };
});
// Note: this can be optimised
});
结果是:
> db.xx.find()
{ "_id" : ObjectId("5161da88ab49f42c329f4228"), "distanceDeviation" : 2, "loc" : [ [ 0, 0 ], [ 10, -10 ], [ 20, 10 ], [ 30, 0 ] ] }
{ "_id" : ObjectId("5161da88ab49f42c329f4229"), "distanceDeviation" : 0.1, "loc" : [ [ 0, 0 ], [ 10, -10 ], [ 20, 10 ], [ 30, 0 ] ] }
>> // run the aggregates
Objects with point near route:
ObjectId("5161da88ab49f42c329f4228")
另一种完全不同的方法是在距离“distanceDeviation”处“绘制”路径周围的闭合多边形,并将其也存储在文档中。这将允许搜索$within: $polygon
(类似于您在圆圈内的搜索),并且还会返回与路线相近但不一定接近其组成点的点的匹配。