Home > Net >  MongoDB $graphLookup query to get degrees of separation
MongoDB $graphLookup query to get degrees of separation

Time:01-27

Mongo graphLookup problem.

I want the num of degrees separation between jerry and superman, the answer should be 2.

In my bi-directional node structure, jerry is connected to lois, louis is connected to superman.

My data

{
    "from" : "jerry",
    "to" : "lois"
}
{
    "from" : "lois",
    "to" : "jerry"
}
{
    "from" : "superman",
    "to" : "lois"
}
{
    "from" : "lois",
    "to" : "superman"
}

The query below returns 4 documents with "degreeOfSeparation" : 4, this represent the bi-directional connections to superman.

db.getCollection("connections").aggregate([
    {
        $graphLookup : {
            from: "connections",
            startWith: "$from",
            connectFromField: "from",
            connectToField: "to",
            maxDepth:5,
            as: "connections"
        }
    },
    {
        $match: {
            "connections.from": "jerry",
            "connections.to": "superman"
        }
    },
    {
        $project: {
            degreeOfSeparation: { $size: "$connections" }
        }
    }

CodePudding user response:

This might works only on level of Grouped nodes

Mongodb playground

db.collection.aggregate([
  {
    $graphLookup: {
      from: "collection",
      startWith: "$to",
      connectFromField: "from",
      connectToField: "from",
      depthField: "connects",
      as: "connections"
    }
  },
  {
    "$match": {
      "$and": [
        {
          from: "superman"
        },
        {
          $or: [
            {
              "connections.to": "jerry"
            },
            {
              to: "jerry"
            }
          ]
        }
      ]
    }
  },
  {
    $project: {
      degreeOfSeparation: {
        $size: "$connections"
      }
    }
  }
])

CodePudding user response:

Here's a way to get your "degreeOfSeparation" "from": "jerry" "to": "superman" and all of the degrees of separation using "$graphLookup"'s "depthField".

db.collection.aggregate([
  {
    "$match": {
      "from": "jerry"  // from here
    }
  },
  {
    $graphLookup: {
      from: "collection",
      startWith: "$to",
      connectFromField: "to",
      connectToField: "from",
      depthField: "depth",
      as: "connections"
    }
  },
  {
    "$set": {
      "allDegsOfSep": {
        "$map": {
          "input": {
            "$filter": {
              "input": "$connections",
              "as": "conn",
              "cond": {"$eq": ["$$conn.to", "superman"]}  // to here
            }
          },
          "as": "toSuperman",
          "in": {
            "$sum": [
              {"$toInt": "$$toSuperman.depth"},
              //  1 zero-based,  1 "to" field
              2
            ]
          }
        }
      }
    }
  },
  {
    "$project": {
      "_id": 0,
      "allDegsOfSep": 1,
      "degreeOfSeparation": {"$min": "$allDegsOfSep"}
    }
  }
])

Try it on mongoplayground.net.

Output using extended collection:

[
  {
    "allDegsOfSep": [5, 2],
    "degreeOfSeparation": 2
  }
]
  • Related