查询GeoJson MultiLineString中的哪个LineString

时间:2015-09-08 03:52:54

标签: mongodb geolocation mongodb-query aggregation-framework geojson

鉴于我有一条公共巴士路线,包括2个主要巴士站。该路由分为2个子路由,以圆形互连,但两者具有相同的路由号。

所以我将routes存储在GeoJson MultiLineString中(在GeoJson中包含2个LineStrings)。 route文档类似于:

{
  "routeName": "A123",
  "route": {
    "type": "MultiLineString",
    "coordinates": [
        [ [100.0, 0.0], [101.0, 1.0], [102.0, 2.0] ],// 1st sub route
        [ [102.0, 2.0], [103.0, 3.0], [100.0, 0.0] ] // 2nd sub route
      ]
  }
}

现在,如果使用$near进行查询,我可以获得整个最近的route文档。但是我想知道最近的子路线或LineString,无论是第一个还是第二个。

是否可以,如果可以,是否可以在一个查询中获得附近的路线和子路线?

1 个答案:

答案 0 :(得分:1)

MongoDB无法分解"一个GeoJSON对象,以匹配"最近的点"就像你想做的那样。因此,你的问题可能更适合于另一种结构,这种结构将使每一个结构停止"停止"被认为是独立的而不是仅仅被表示为" LineString"。

在查询中使用此方法的一种非常有效的方法是:

{
  "routename": "A123",
  "stops": [
    { 
      "type": "out",
      "location": {
        "type": "Point",
        "coordinates": [100.0,0.0]
      }
    },
    { 
      "type": "out",
      "location": {
        "type": "Point",
        "coordinates": [101.0,1.0]
      }
    },
    { 
      "type": "return",
      "location": {
        "type": "Point",
        "coordinates": [102.0,2.0]
      }
    },
    { 
      "type": "return",
      "location": {
        "type": "Point",
        "coordinates": [103.0,3.0]
      }
    }
  ]
}

分解每个"停止"在通往一个独特的"点"的路线上,以及保持路线"类型"表示停止是否在" out"或"返回"旅行的一段。

然后,您可以使用$geoNear运行此聚合查询,以匹配和投射最近的点"从数组条目。下一阶段将匹配的位置与每个"停止"在数组中,为了提取该句点所属的路径的分支:

db.routes.aggregate([ 
  { "$geoNear": {
    "near": {
      "type": "Point",
      "coordinates": [103.0, 2.0]
    },
    "distanceField": "distance",
    "spherical": true,
    "includeLocs": "loc"
  }},
  { "$project": {
    "routeName": 1,
    "distance": 1,
    "route": {
      "$let": {
        "vars": {
          "matchedStop": {
            "$setDifference": [
              { "$map": {
                "input": "$stops",
                "as": "stop",
                "in": {
                  "$cond": [
                    { "$eq": [ "$$stop.location", "$loc" ] },
                    "$$stop",
                    false
                  ]
                }
              }},
              [false]
            ]
          }
        },
        "in": {
          "$setDifference": [
            { "$map": {
              "input": "$stops",
              "as": "stop",
              "in": {
                "$cond": [
                  { "$setEquals": [
                    { "$map": { "input": ["A"], "as": "el", "in": "$$stop.type" } },
                    "$$matchedStop.type"
                  ]},
                  { 
                    "type": "$$stop.type",
                    "location": "$$stop.location",
                    "nearest": {
                      "$eq": [ "$$stop.location", "$loc" ]
                    }
                  },
                  false
                ]
              }
            }},
            [false]
          ]
        }
      }
    }
  }}
])

这将为您提供此类输出:

{
    "_id" : ObjectId("55ee6c0a2343a0d2e1650e28"),
    "distance" : 111251.03086891436,
    "route" : [
            {
                    "type" : "return",
                    "location" : {
                            "type" : "Point",
                            "coordinates" : [
                                    102,
                                    2
                            ]
                    },
                    "nearest" : true
            },
            {
                    "type" : "return",
                    "location" : {
                            "type" : "Point",
                            "coordinates" : [
                                    103,
                                    3
                            ]
                    },
                    "nearest" : false
            }
    ]
}

这主要是$map的大量使用,以便提取所需的元素。所以第一种情况是提取已经在" includeLocs"中识别的匹配元素。从$geoNear返回。然后,这允许您重新处理数组并仅过滤掉"元素"包含相同的"类型"对于路线的路段,为了增加好处,我们还标记当阵列成员实际上是"最近的"匹配。

特别是路线"类型"为了匹配,来自早期$map的返回变量实际上是一个数组。因此,您只能将数组与另一个"数组"进行比较,这就是为什么$map再次用于对抗奇异字段值,以便将其转换为数组本身:

{ "$setEquals": [
  { "$map": { "input": ["A"], "as": "el", "in": "$$stop.type" } },
  "$$matchedStop.type"
]},

这就是那部分的全部内容,当然$setEquals测试两个数组以确定它们实际上是否相同。

这里的其他内容是$let,以便获得" matchedStop"更容易访问,$setDifference基本上通过$cond运算符从数组成员的测试中过滤掉false的任何返回值。

当然,这里的替代方案基本上只是将每个"停止"将它放入集合中的自己的文档中,然后运行一个查询来查找最近的"最近的"文档和另一个查询来查找相同的" route"和其他停在同一条腿上的#34;您的退货信息中的那条路线。但是这仍然是自包含在一个文档中并且匹配并且将非常有效,特别是对于多个" route"匹配。