这些是我收藏中的示例文档,我们称其为bus_routes:
{
"_id":{
"$oid":"56e9b39c732b6122f878576ba"
},
"src_busStop":"A",
"dst_busStop":"B",
"bus":"7318 FAF"
}
{
"_id":{
"$oid":"56e9b39c732b6122f878576bb"
},
"src_busStop":"B",
"dst_busStop":"C",
"bus":"7319 FAF"
}
{
"_id":{
"$oid":"56e9b39c732b6122f878576bc"
},
"src_busStop":"C",
"dst_busStop":"D",
"bus":"7320 FAF"
}
我想选择城市A和D之间的所有连接(所有公交车),最大转乘次数为3。我的猜测是我应该使用$graphLookup
,但是我不知道如何实现它。预先感谢。
当图形中只有一条路径时,graphLookup运算符最有效。
对于具有多个路径的公交路线,沿路径的每个文档将以平面数组形式返回。然后,您将需要进一步处理列表以实际构建路由序列。
这些阶段应该为您提供所有从“ A”开始的路线。
maxDepth:2
将最多返回3个转出,restrictSearchWithMatch:{dst:{$ne:"A"}}
将忽略返回“ A”的所有路由。
{$match:{src_busStop:"A"}},
{$graphLookup:{
from:"bus_routes",
startWith:"$dst_busStop",
connectFromField:"dst_busStop",
connectToField:"src_busStop",
as:"routes",
maxDepth:2,
depthField:"transfers",
restrictSearchWithMatch:{dst:{$ne:"A"}}
}}
请注意,没有简单的方法将其限制为以“ D”结尾的路径。由graphLookup填充的“ routes”数组将包含all“ bus_routes”文档,可以从“ A”进行3次传输。
编辑
经过进一步思考,这可以通过3个单独的非递归查找来完成,这可能是获取信息并使路由分开的方式。
这里是一个示例管道,用于查找从“ A”到“ D”的路由。这对我来说有点蛮力,但是我还没有一个更优雅的解决方案。步骤是:
db.bus_routes.aggregate([
{$match:{src_busStop:"A"}},
{$addFields:{route:["$$ROOT"]}},
{$lookup:{from:"bus_routes",localField:"dst_busStop",foreignField:"src_busStop",as:"firstxfer"}},
{$unwind:"$firstxfer"},
{$match:{"firstxfer.dst_busStop":{$ne:"A"}}},
{$addFields:{firstxfer:{$cond:[{$eq:["D","$firstxfer.src_busStop"]},[],"$firstxfer"]}}},
{$lookup:{from:"bus_routes",localField:"firstxfer.dst_busStop",foreignField:"src_busStop",as:"secondxfer"}},
{$unwind:"$secondxfer"},
{$match:{"secondxfer.dst_busStop":{$ne:"A"}}},
{$addFields:{secondxfer:{$cond:[{$eq:["D","$secondxfer.src_busStop"]},[],"$secondxfer"]}}},
{$lookup:{from:"bus_routes",localField:"secondxfer.dst_busStop",foreignField:"src_busStop",as:"thirdxfer"}},
{$unwind:"$thirdxfer"},
{$addFields:{thirdxfer:{$cond:[{$eq:["D","$thirdxfer.src_busStop"]},[],"$thirdxfer"]}}},
{$project:{
route:["$thirdxfer","$secondxfer","$firstxfer","$route"]
}},
{$match:{"route.dst_busStop":"D"}},
{$project:{
route:{
$reduce:{
input:"$route",
initialValue:[],
in:{$cond:[
{$or:[{$eq:["D","$$this.dst_busStop"]},{$gt:[{$size:"$$value"},0]}]},
{$concatArrays:[["$$this"],"$$value"]},
"$$value"
]}
}
}
}},
{$group:{
_id:null,
route:{$addToSet:"$route"}
}},
{$unwind:"$route"},
{$addFields:{ buses:{$size:"$route"}}},
{$sort:{buses:1}}
])
我在Playground中设置了一个测试数据集来演示这一点。