mongodb是指查询中文档的属性

时间:2013-03-19 16:12:04

标签: mongodb geospatial

我有一个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来做。

1 个答案:

答案 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(类似于您在圆圈内的搜索),并且还会返回与路线相近但不一定接近其组成点的点的匹配。

有关manualaggregate()$geoNear

的更多信息,请参阅$polygon