mongodb - 如何使用 MongoDB 图查找?
问题描述
这些是我收藏的示例文档,假设它被称为 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”数组将包含所有“bus_routes”文档,这些文档可以在从“A”的 3 次传输中到达。
编辑
经过进一步思考,这可以通过 3 个单独的非递归查找来完成,这可能是获取信息并保持路由分开的方式。
这是一个示例管道,用于查找从“A”到“D”的路线。这对我来说感觉有点蛮力,但我还没有更优雅的解决方案。步骤是:
- 选择从起点出发的所有路线
- 将原始文档保存在“路线”字段中以供以后使用
- 查找从下一个可达站出发的所有路线,存储在“firstxfer”字段中
- 展开 firstxfers,以便我们可以分别考虑每条路线
- 丢弃所有返回其来源地的路线
- 重复3-5生成secondxfer和thirdxfer
- 在“路线”字段中,将原始单据和各中转单据倒序合并
- 减少数组,消除到达目的地后的所有路线,并颠倒顺序
- 使用 addToSet 分组以消除重复路由
- 再次展开路线,以便我们可以排序
- 在“公共汽车”字段中添加所需的路线数量
- 排序,让最短的路线排在第一位
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:{path: "$secondxfer", preserveNullAndEmptyArrays: true}},
{$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: {path: "$thirdxfer", preserveNullAndEmptyArrays: true}},
{$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中设置了一个测试数据集来演示这一点。
推荐阅读
- arrays - 通过串行在arduino中构建具有可变长度元素的缓冲区数组
- android - 如何阻止新的推送通知被 Firebase 中的旧推送通知替换?
- azure - 通过 POSTMAN 访问时无法获取事件中心描述
- python - 在阻止亚马逊云的公司防火墙后面使用 Anaconda 和 conda-forge
- google-apps-script - 使用 ScriptApp.getProjectTriggers() 导致服务器错误
- git - cf login - Windows GIT 运行器中的凭据作为 shell 被拒绝
- java - 如何自动触发可执行 JAR 文件
- javascript - Html / JS:将一个表的一列的单元格值与另一个表的另一列的单元格链接
- hiveql - 以毫秒为单位查找日期差异
- sorting - 在 AIX 中对 3 个字母月份进行排序的命令