鉴于我有一条公共巴士路线,包括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
,无论是第一个还是第二个。
是否可以,如果可以,是否可以在一个查询中获得附近的路线和子路线?
答案 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"匹配。