Upsert multilevel nested object in every level

As i writed in the previous comment, i found a solution.
And now i post it with some description, maybe it will help someone.

Big thanks to @Prasad_Saya, who made a solution to a similar problem in here: Prasad_Saya’s post
The only difference is that, this solution works only with two level. And i needed a three level solution.

I used a same $reduce method to produce this object: { "items":[...], "updated":true } but after i transformed the object to the original array with a $let and not with a new aggregation step.

The process is:

  • First i search the “A” object with a query filter and upsert it if not exists. (This is the easy part)
  • After i found the “A” object, i reduce the “b” array inside it. The reduce produce this object { "items":[...], "updated":true } with the updated array and "updated":true, or if the id not found then the unmodified array and "updated":false.
  • After this, i transform the object with a $let. If updated==true then simply write the array or else add a new element to the array.
  • And i made the same steps with the “c” array inside the “B” object.

And the full update pipeline is:

db.collection.update({
  "a_id": A_ID
},
[
   {
    $set: {
      count: {
        $add: [
          {
            $ifNull: [
              "$count",
              0
            ]
          },
          1
        ]
      },
      b: {
        $let: {
          vars: { "data":
            {
              $reduce: {
                input: {
                  $ifNull: [
                    "$b",
                    []
                  ]
                },
                initialValue: {
                  "items": [],
                  "updated": false
                },
                in: {
                  $cond: [
                    {
                      $eq: [
                        "$$this.b_id",
                        B_ID
                      ]
                    },
                    {
                      "items": {
                        $concatArrays: [
                          "$$value.items",
                          [
                            {
                              "b_id": "$$this.b_id",
                              "count": {
                                $add: [
                                  "$$this.count",
                                  1
                                ]
                              },
                              "c": {
                                $let: {
                                  vars: { "data":
                                    {
                                      $reduce: {
                                        input: {
                                          $ifNull: [
                                            "$$this.c",
                                            []
                                          ]
                                        },
                                        initialValue: {
                                          "items": [],
                                          "updated": false
                                        },
                                        in: {
                                          $cond: [
                                            {
                                              $eq: [
                                                "$$this.c_id",
                                                C_ID
                                              ]
                                            },
                                            {
                                              "items": {
                                                $concatArrays: [
                                                  "$$value.items",
                                                  [
                                                    {
                                                      "c_id": "$$this.c_id",
                                                      "count": {
                                                        $add: [
                                                          "$$this.count",
                                                          1
                                                        ]
                                                      }
                                                    }
                                                  ]
                                                ]
                                              },
                                              "updated": true
                                            },
                                            {
                                              "items": {
                                                $concatArrays: [
                                                  "$$value.items",
                                                  [
                                                    "$$this"
                                                  ]
                                                ]
                                              },
                                              "updated": "$$value.updated"
                                            }
                                          ]
                                        }
                                      }
                                    }
                                  },
                                  in: {
                                    $cond: [
                                      {
                                        $eq: [
                                          "$$data.updated",
                                          false
                                        ]
                                      },
                                      {
                                        $concatArrays: [
                                          "$$data.items",
                                          [
                                            {
                                              "c_id": C_ID,
                                              "count": 1
                                            }
                                          ]
                                        ]
                                      },
                                      {
                                        $concatArrays: [
                                          "$$data.items",
                                          []
                                        ]
                                      }
                                    ]
                                  }
                                }
                              }
                            }
                          ]
                        ]
                      },
                      "updated": true
                    },
                    {
                      "items": {
                        $concatArrays: [
                          "$$value.items",
                          [
                            "$$this"
                          ]
                        ]
                      },
                      "updated": "$$value.updated"
                    }
                  ]
                }
              }
            }
          },
          in: {
            $cond: [
              {
                $eq: [
                  "$$data.updated",
                  false
                ]
              },
              {
                $concatArrays: [
                  "$$data.items",
                  [
                    {
                      "b_id": B_ID,
                      "count": 1,
                      "c": [
                        {
                          "c_id": C_ID,
                          "count": 1,
                          
                        }
                      ]
                    }
                  ]
                ]
              },
              {
                $concatArrays: [
                  "$$data.items",
                  []
                ]
              }
            ]
          }
        },
        
      }
    }
  }
],
{
  "upsert": true
})
1 Like