2013-03-19 98 views
1

我有一个MongoDB的收集,在那里我有文件结构如下MongoDB的参考文档的属性查询

{ 
    ... 
    distanceDeviation: 2.0, 

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

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

我想有一个查询在那里,如果我把它两点蒙戈返回我文件收集,其中有两个在他们loc阵列的点。

我已经能够用固定$radius参数做使用$within如下:

{ 
    "$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

没有,也没办法)来传递一个变量来查找(这是基于文档中的字段。我不推荐在其他许多方面使用$ where性能原因 - 如果你展开这些数据代表的是什么,也许有不同的方式来构造数据(如果你有这个选项),以获得你想要的定期查询? – 2013-03-19 16:17:46

+0

有可能重构文档。本文档中的loc变量仅表示路线,distanceDeviation表示该路线允许多少灵活性。我应该检查另一个startPoint,endPoint是否在这条路线内。 – 2013-03-19 16:44:13

回答

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(类似于您在圈内的搜索),并且还会为靠近路线但不一定靠近其构成点之一的点返回匹配。

请参阅manual的更多信息,aggregate()$geoNear$polygon