1

I built up a graph structure using MongoDB. I did some complex queries on this structure already, but I am struggling on selecting a subgraph of a given depth starting from a specific node via the aggregation pipeline.

I already did use the $graphLookup to get all the required nodes, which gives the following result:

{ "_id" : "O_4", "name" : "D", "type" : "Info", "links" : [ { "link" : "L_2", "objectId" : "O_1" }, { "link" : "L_4", "objectId" : "O_3" }, { "link" : "L_10", "objectId" : "O_6" } ] }
{ "_id" : "O_2", "name" : "B", "type" : "Info", "links" : [ { "link" : "L_1", "objectId" : "O_1" }, { "link" : "L_3", "objectId" : "O_3" } ] }
{ "_id" : "O_1", "name" : "A", "type" : "Info", "links" : [ { "link" : "L_1", "objectId" : "O_2" }, { "link" : "L_2", "objectId" : "O_4" } ] }
{ "_id" : "O_3", "name" : "C", "type" : "Info", "links" : [ { "link" : "L_3", "objectId" : "O_2" }, { "link" : "L_4", "objectId" : "O_4" }, { "link" : "L_5", "objectId" : "O_5" }, { "link" : "L_6", "objectId" : "O_7" } ] }
{ "_id" : "O_6", "name" : "F", "type" : "System", "links" : [ { "link" : "L_8", "objectId" : "O_7" }, { "link" : "L_9", "objectId" : "O_5" }, { "link" : "L_10", "objectId" : "O_4" } ] }

But now I want to remove the nested "link" objects (in array "links") where the "objectId" is not present in the above result, i.e. in "O_6" the link "L_8" should be removed, since the node "O_7" is not part of the subgraph.

I already tried playing around with $in, $facet and other stuff to get this problem solved, but it seems like I am unable ...

Maybe, you guys can help out?

Edit:

Just found a solution more or less - $filter does a decent job here:

{
    $unwind: "$links"
}, {
    $group: {
      _id: null,
      ids: {
        $addToSet: "$_id"
      },
      links: {
        $addToSet: "$links"
      }
    }
}, {
    $project: {
        links: {
            $filter: {
                input: "$links",
                as: "link",
                cond: {
                    $in: ["$$link.objectId", "$ids"] 
                }
            }
        }
    }
}, {
    $unwind: "$links"
}, {
    $replaceRoot: {
        newRoot: "$links"
    }
}, {
    $group: {
      _id: "$link"
    }
}

Returns what I needed - the list of Link-IDs:

{ "_id" : "L_1" }
{ "_id" : "L_10" }
{ "_id" : "L_3" }
{ "_id" : "L_2" }
{ "_id" : "L_4" }
Rennnyyy
  • 86
  • 5
  • 1
    So in your example you want to remove all links to nodes that are not in `["O_4", "O_2", "O_1", "O_3", "O_6"]`? If so then using a `restrictSearchWithMatch` with `{ objectId: { $in: ids } }` should solve the problem. – als Apr 01 '20 at 14:22
  • Yeah, that is the idea. But those `links` are part of the node and not generated by `$graphLookup`. The result you see above is already a "flattened" list of the result that `$graphLookup` generates. Does this approach work then? I'll test tomorrow on my environment again ... – Rennnyyy Apr 01 '20 at 15:39
  • If they are already a part of the node you can remove them with a [`$filter`](https://docs.mongodb.com/manual/reference/operator/aggregation/filter/) in the previous pipeline step. – als Apr 01 '20 at 15:48
  • Cheers! Made my day! – Rennnyyy Apr 01 '20 at 16:14
  • Does this answer your question? [How to filter array in subdocument with MongoDB](https://stackoverflow.com/questions/15117030/how-to-filter-array-in-subdocument-with-mongodb) – whoami - fakeFaceTrueSoul Apr 01 '20 at 20:20

0 Answers0