Search code examples
mongodbmongooseaggregation-framework

How to update all child documents of match criteria using graph lookup?


I want to do the opposite of this. I want to create a tag field on the childs of _id: 1 document. Just the thing is that the match criteria is dynamic. So Whoever matches the $match criteria I want to set tags on the childs of those matched document with the help of $graphLookup.

Mongo Playground Example

Like this

db.collection.aggregate([
  { // This part is fully dynamic could be anything here. 
    "$match": {
      name: "C:"
    }
  },
  //Make a graph lookup so that update happens on childs
  {
    $set:{
      tags:["#new","#cool","#vibes"]
    }
  }
])

Example dataset:

[
  {
    "_id": 1,
    "name": "C:"
  },
  {
    "_id": 2,
    "parentFolderId": 1,
    "name": "Users"
  },
  {
    "_id": 3,
    "parentFolderId": 2,
    "name": "<username>"
  },
  {
    "_id": 4,
    "parentFolderId": "3",
    "name": "Desktop"
  },
  {
    "_id": 5,
    "parentFolderId": "4",
    "name": "alpha.tsx"
  },
  {
    "_id": 6,
    "parentFolderId": "1",
    "name": "Program Files"
  },
  {
    "_id": 7,
    "parentFolderId": "1",
    "name": "System32"
  },
  {
    "_id": 8,
    "parentFolderId": "1",
    "name": "Program Files(x86)"
  }
]

As much I understand graph lookup can help me update the parents of a document but not childs. And even if there is some way how would one parent document will be mapped to multiple child documents in aggregation pipeline.


Solution

  • One option is to use $graphLookup and then $match all documents that contains the wanted parent:

    db.collection.aggregate([
      {$graphLookup: {
          from: "collection",
          startWith: "$parentFolderId",
          connectFromField: "parentFolderId",
          connectToField: "_id",
          as: "parents"
      }},
      {$match: {$expr: {$eq: [{$in: ["C:", "$parents.name"]}, true]}}},
      {$unset: "parents"},
      {$set: {tags: ["#new", "#cool", "#vibes"]}},
      {$merge: {into: "collection"}}
    ])
    

    See how it works on the playground example