2

我有一个 MongoDB集合,其中有具有以下结构的文档

{
   ...
   distanceDeviation: 2.0,

   loc: [
      [24.77, 67.5],
      [24.78, 67.6],
      [24.79, 67.7],
      [24.80, 67.8],
      ...
   ]
   ...
}

我有这个集合地理索引(使用ensureIndex on loc)。

我想要一个查询,如果我发送两个点 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.

4

1 回答 1

0

虽然有点尴尬,但有可能aggregate()与它的$geoNear操作员一起完成这项工作。尴尬,因为聚合只允许一个$geoNear,它必须位于聚合管道的顶部。所以,我们必须做两个聚合,然后合并结果。

这个想法:$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(类似于您在圆圈内的搜索),并且还将返回匹配路线附近但不一定靠近其组成点之一的点。

请参阅手册以获取有关aggregate()$geoNear$polygon的更多信息

于 2013-04-07T21:19:57.240 回答