在MongoDB中,如何使用文档中的字段作为$ geoWithin / $ centerSphere表达式的输入?

时间:2018-02-13 05:39:22

标签: mongodb mongodb-query aggregation-framework geospatial

我试图编写一个MongoDB查询,搜索以指定位置为中心的半径范围内的文档。

以下查询有效。它会查找searching.radius弧度searching.coordinates范围内的所有文档。

但是,我想要做的是将当前文档allowed_radius值添加到searching.radius值,以便允许的范围实际上更大。

如何判断此查询以使其成为可能?

提交查询

collection.aggregate([
        {
            $project:{
                location: "$location",
                allowed_radius: "$allowed_radius"
            }
        },
        {
            $match: {
                $and:
                    [
                        { location: { $geoWithin: { $centerSphere: [ searching.coordinates, searching.radius ] }}},
                        {...},
                    ...]
                ...}
]);

我想做什么(伪查询)

collection.aggregate([
        {
            $project:{
                location: "$location",
                allowed_radius: "$allowed_radius"
            }
        },
        {
            $match: {
                $and:
                    [
                        { location: { $geoWithin: { $centerSphere: [ searching.coordinates, { $add: [searching.radius, $allowed_radius]} ] }}},
                        {...},
                    ...]
                ...}
]);

1 个答案:

答案 0 :(得分:5)

我尝试使用n <- 0 for(ii in 1:11){ for(jj in 1:11){ w <- ii x <- jj y <- 4 z <- 7 coord1 <- c(w, x) coord2 <- c(y, z) new_coord <- rbind(coord1, coord2) if(sum(duplicated(new_coord)) > 0) n <- n+1 #or #if(anyDuplicated(new_coord) > 0) n <- n+1 print(n) }} n #[1] 1 ,但无法以这种方式工作。

以下是使用$geoNear运算符执行此操作的另一种方法:

鉴于此输入:

$geoWithin / $centerSphere

这个索引($ geoNear需要):

db.collection.insert({
  "airport": "LGW",
  "id": 1,
  "location": { type: "Point", coordinates: [-0.17818, 51.15609] },
  "allowed_radius": 100
})
db.collection.insert({
  "airport": "LGW",
  "id": 2,
  "location": { type: "Point", coordinates: [-0.17818, 51.15609] },
  "allowed_radius": 0
})
db.collection.insert({
  "airport": "ORY",
  "id": 3,
  "location": { type: "Point", coordinates: [2.35944, 48.72528] },
  "allowed_radius": 10
})

使用searching.radius = 1000:

db.collection.createIndex( { location : "2dsphere" } )

将返回id为1(距离= 1002 <=半径= 1000 + 100)和3(距离= 676 <=半径= 1000 + 10)并丢弃id 2(距离= 1002> 1000 + 0)的文档)。

db.collection.aggregate([ { $geoNear: { near: { "type" : "Point", "coordinates": [7.215872, 43.658411] }, distanceField: "distance", spherical: true, distanceMultiplier: 0.001 }}, { $addFields: { radius: { "$add": ["$allowed_radius", 1000] } } }, { $addFields: { isIn: { "$subtract": ["$distance", "$radius" ] } } }, { $match: { isIn: { "$lte": 0 } } } ]) 参数用于将单位恢复为km。

$ geoNear必须是聚合的第一阶段(由于我认为使用了索引),但$ geoNear的其中一个参数是其他字段的匹配查询。

即使它需要地理位置索引,您也可以为索引添加其他维度。

$ geoNear不会将位置字段作为参数,因为它要求集合具有地理索引。因此,$ geoNear隐式地使用索引的位置字段(无论字段的名称)。

最后,我很确定最后阶段可以简化。

$ geoNear阶段仅用于投影每条记录的距离:

distanceMultiplier

实际上,geoNear运算符需要使用{ "airport" : "ORY", "distance" : 676.5790971238937, "location" : { "type" : "Point", "coordinates" : [ 2.35944, 48.72528 ] }, "allowed_radius" : 10, "id" : 3 } { "airport" : "LGW", "distance" : 1002.3351814526812, "location" : { "type" : "Point", "coordinates" : [ -0.17818, 51.15609 ] }, "allowed_radius" : 100, "id" : 1 } { "airport" : "LGW", "distance" : 1002.3351814526812, "location" : { "type" : "Point", "coordinates" : [ -0.17818, 51.15609 ] }, "allowed_radius" : 0, "id" : 2 } 参数,该参数用于在查询的下一个阶段为每个记录投影计算的距离。在聚合结束时,返回的记录如下所示:

distanceField

如有必要,您可以删除查询生成的字段(距离,半径,isIn)以及最终的$ project阶段。例如:{ "airport" : "ORY", "location" : { "type" : "Point", "coordinates" : [ 2.35944, 48.72528 ] }, "allowed_radius" : 10, "id" : 3, "distance" : 676.5790971238937, "radius" : 1010, "isIn" : -333.4209028761063 }