Get full tree from parent in mongodb

128 Views Asked by At

I use a MongoDB database with a collection, using a tree parent-children References.

Each document in the collection includes a property: parentId.The parentId property is an (ObjectId) reference to the parent document and It can be null.

Sample:

[{
  "_id": {
    "$oid": "64d9f2bb7a587e250e3acb45"
  },
  "isActive": true,
  "name": "Test1"
}, {
  "_id": {
    "$oid": "64dc481d37a38cb58de04ffb"
  },
  "isActive": true,
  "name": "Test2"
}, {
  "_id": {
    "$oid": "64d9dd9f7a587e250e3ac95b"
  },
  "isActive": true,
  "name": "Test1-1",
  "parentId": {
    "$oid": "64d9f2bb7a587e250e3acb45"
  }
}, {
  "_id": {
    "$oid": "64dca02f0ff1ddfc4e40a874"
  },
  "isActive": true,
  "name": "Test1-1-1",
  "parentId": {
    "$oid": "64d9dd9f7a587e250e3ac95b"
  }
}]

I used $graphLookup but It only fetch all childrens in one list field. That I need it to populate a recursive tree structure from parent to children such as:


{
  "_id": {
    "$oid": "64d9f2bb7a587e250e3acb45"
  },
  "isActive": true,
  "name": "Test1",
  "childrents": [
    {
      "_id": {
        "$oid": "64d9dd9f7a587e250e3ac95b"
      },
      "name": "Test1-1",
      "isActive": true,
      "childrents": [
        {
            "_id": {
                "$oid": "64dca02f0ff1ddfc4e40a874"
             },
            "isActive": true,
            "name": "Test1-1-1",
            "childrents": []
        }
      ]
    }
  ]
}, {
  "_id": {
    "$oid": "64dc481d37a38cb58de04ffb"
  },
  "isActive": true,
  "name": "Test2",
  "childrents": []
}

Thank you so much for your help, I really appreciate it!

1

There are 1 best solutions below

0
TanThien On BEST ANSWER

After researching I found a solution below https://mongoplayground.net/p/Fp5LlivVzlX. Anyone with a better solution please let me know. Thanks

[{
 $graphLookup: {
  from: 'collection',
  startWith: '$_id',
  connectFromField: '_id',
  connectToField: 'parentId',
  as: 'childrens',
  restrictSearchWithMatch: {
   isActive: true
  },
  depthField: 'level'
 }
}, {
 $unwind: {
  path: '$childrens',
  preserveNullAndEmptyArrays: true
 }
}, {
 $sort: {
  'childrens.level': -1
 }
}, {
 $group: {
  _id: '$_id',
  parentId: {
   $first: '$parentId'
  },
  isActive: {
   $first: '$isActive'
  },
  name: {
   $first: '$name'
  },
  childrens: {
   $push: '$childrens'
  }
 }
}, {
 $addFields: {
  childrens: {
   $reduce: {
    input: '$childrens',
    initialValue: {
     level: -1,
     presentChild: [],
     prevChild: []
    },
    'in': {
     $let: {
      vars: {
       prev: {
        $cond: [
         {
          $eq: [
           '$$value.level',
           '$$this.level'
          ]
         },
         '$$value.prevChild',
         '$$value.presentChild'
        ]
       },
       current: {
        $cond: [
         {
          $eq: [
           '$$value.level',
           '$$this.level'
          ]
         },
         '$$value.presentChild',
         []
        ]
       }
      },
      'in': {
       level: '$$this.level',
       prevChild: '$$prev',
       presentChild: {
        $concatArrays: [
         '$$current',
         [
          {
           $mergeObjects: [
            '$$this',
            {
             childrens: {
              $filter: {
               input: '$$prev',
               as: 'e',
               cond: {
                $eq: [
                 '$$e.parentId',
                 '$$this._id'
                ]
               }
              }
             }
            }
           ]
          }
         ]
        ]
       }
      }
     }
    }
   }
  }
 }
}, {
 $addFields: {
  childrens: '$childrens.presentChild'
 }
}]