如何使用MongoDB图形查找?

问题描述 投票:0回答:1

这些是我收藏中的示例文档,我们称其为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,但是我不知道如何实现它。预先感谢。

mongodb mongodb-query
1个回答
0
投票

当图形中只有一条路径时,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”的路由。这对我来说有点蛮力,但是我还没有一个更优雅的解决方案。步骤是:

  1. 选择从起点出发的所有路线
  2. 将原始文档保存在“路线”字段中,以备后用
  3. 查找来自下一个可到达站点的所有路由,存储在“ firstxfer”字段中
  4. 放开firstxfers,以便我们可以分别考虑每条路线
  5. 丢弃所有返回原点的路线
  6. 重复3-5生成secondxfer和thirdxfer
  7. 在“路径”字段中以相反的顺序合并原始文档和每个传输文档
  8. 减少数组,在到达目的地后消除所有路由,并反转顺序
  9. 使用addToSet分组以消除重复的路由
  10. 再次展开路线,以便我们进行排序
  11. 在“公共汽车”字段中添加所需的路线数
  12. 排序,以最短的路线在前
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中设置了一个测试数据集来演示这一点。

© www.soinside.com 2019 - 2024. All rights reserved.