GraphLookup matching multiple fields

Hello,

I am having trouble getting an aggregation to work as I want it due to me having a more complex data type that I want to match.

My data consists of several “events” that are being sent within a CI/CD system. These events can link to each other using link types and the ID of the event that they link to.
Example: {“type”: “CAUSE”, “target”: MyID} - My event is sent because of “MyID”.

This data can be considered a graph and, as such, using GraphLookup seems correct. My problem is that there can be multiple links with different link types to different events and I want to restrict my search to only see a certain link type.
For instance, I only want to do a graph lookup of events that have a Target to my ID AND that link is a CAUSE link.

Sample data. Event with data.name: “5” has a link to “4”, but it is a CONTEXT link, not CAUSE. But since there is a CAUSE link (to an event that’s not in the graph) I get it in my aggregation.

[
  {
    "data": {
      "name": "Base"
    },
    "meta": {
      "id": "bb4a4578-7947-41ec-bdc9-d8be16ae6efa",
      "type": "EiffelActivityTriggeredEvent"
    }
  },
  {
    "data": {
      "name": "1"
    },
    "links": [
      {
        "target": "bb4a4578-7947-41ec-bdc9-d8be16ae6efa",
        "type": "CAUSE"
      }
    ],
    "meta": {
      "id": "dc4ff5a0-9a09-4931-92f3-e62127b967f8",
      "type": "EiffelActivityTriggeredEvent"
    }
  },
  {
    "data": {
      "name": "2"
    },
    "links": [
      {
        "target": "dc4ff5a0-9a09-4931-92f3-e62127b967f8",
        "type": "CAUSE"
      }
    ],
    "meta": {
      "id": "2a00b3f5-143c-4dde-bc77-4127a61d0410",
      "type": "EiffelActivityTriggeredEvent"
    }
  },
  {
    "data": {
      "name": "3"
    },
    "links": [
      {
        "target": "2a00b3f5-143c-4dde-bc77-4127a61d0410",
        "type": "CAUSE"
      }
    ],
    "meta": {
      "id": "93b97903-32da-4de4-87bd-ddc633c7c741",
      "type": "EiffelActivityTriggeredEvent"
    }
  },
  {
    "data": {
      "name": "4"
    },
    "links": [
      {
        "target": "93b97903-32da-4de4-87bd-ddc633c7c741",
        "type": "CAUSE"
      }
    ],
    "meta": {
      "id": "986de1a4-b376-481a-893d-a735ae0eaf87",
      "type": "EiffelActivityTriggeredEvent"
    }
  },
  {
    "data": {
      "name": "5"
    },
    "links": [
      {
        "target": "986de1a4-b376-481a-893d-a735ae0eaf87",
        "type": "CONTEXT"
      },
      {
        "target": "d73497e7-a1a1-496c-9f48-cceb5d5db210",
        "type": "CAUSE"
      }
    ],
    "meta": {
      "id": "aa2e4a69-04d4-42a4-b034-938f71f77ed9",
      "type": "EiffelActivityTriggeredEvent"
    }
  }
]

Sample query:

db.collection.aggregate({
  "$match": {
    "meta.id": "bb4a4578-7947-41ec-bdc9-d8be16ae6efa"
  }
},
{
  "$graphLookup": {
    "from": "collection",
    "startWith": "$meta.id",
    "connectFromField": "meta.id",
    "connectToField": "links.target",
    "as": "ActT",
    "maxDepth": 4
    "restrictSearchWithMatch": {
      "links.type": "CAUSE"
    }
  }
},
{
  "$unwind": {
    "path": "$ActT"
  }
},
{
  "$replaceRoot": {
    "newRoot": "$ActT"
  }
},
{
  "$sort": {
    "data.name": 1
  }
})

Link to mongoplayground: Mongo playground

Is there a way to do an aggregation query where it will only get events that have a CAUSE link to the meta.id of the parent, and nothing else.

Thank you!

I am not sure I understand so the following might be stupid.

Can’t you simply add

"meta.id": "bb4a4578-7947-41ec-bdc9-d8be16ae6efa"

to

inside the restrictSearchWithMatch.

That would, sadly, only help on the first depth where the startWith is used. Since each event on every depth has a new meta.id value that would need to be used in restrictSearchWithMatch and this value is, as far as I know, not available in restrictSearchWithMatch.

I knew I did not understood something correctly.

The only think I can think at this point is that connectFromField and connectToField might be objects rather than simple values. I would not know how you could leverage this fact but I have a small example.

mongosh > c.find()
{ _id: ObjectId("638609e736e25a0dff0d1097"),
  data: { name: 10 },
  meta: { id: 1, cause: 2 } }
{ _id: ObjectId("63860a4936e25a0dff0d1098"),
  data: { name: 12 },
  meta: { id: 1, cause: 2 } }

match = { "$match" : { "data.name" : 10 } }
/* output suppressed */

mongosh > graphLookup = { "$graphLookup" : {
    "from" : "Tobias_Persson" ,
    "startWith" : "$meta" ,
    "connectFromField" : "meta" ,
    "connectToField" : "meta" ,
    "as" : "_result"  } }
/* output suppressed */

mongosh > db.Tobias_Persson.aggregate( [ match , graphLookup ] )
{ _id: ObjectId("638609e736e25a0dff0d1097"),
  data: { name: 10 },
  meta: { id: 1, cause: 2 },
  _result: 
   [ { _id: ObjectId("63860a4936e25a0dff0d1098"),
       data: { name: 12 },
       meta: { id: 1, cause: 2 } },
     { _id: ObjectId("638609e736e25a0dff0d1097"),
       data: { name: 10 },
       meta: { id: 1, cause: 2 } } ] }

I do not know if you could modify your schema to use objects in connectFrom/ToField but it is a starting that might gives you some ideas.