Search code examples
mongodbaggregation

MongoDB conditional aggregation with unwind


I have db collection like:

{
  "_id" : "af5c00e4-d3a8-419d-8793-c0cf328802ec",
    "collaborators" : [
        {
            "_id" : "9bd2eee8-bf6c-4c6f-bab7-d2d175aed807",
            "origin" : [
                {
                    "originId" : "123"
                }
            ],
            "firstName" : "Parveen",
            "lastName" : "Vendor",
            "email" : "[email protected]"
        },
        {
            "_id" : "234324-bf6c-4c6f-bab7-d2d175aed807",
            "origin" : [
                {
                    "originId" : "1234"
                }
            ],
            "firstName" : "Parveen123",
            "lastName" : "34",
            "email" : "[email protected]"
        }
    ],
    "orders" : [
        {
            "totalAmount" : 10,
            "collaborators" : [
                {
                    "origin" : [
                        {
                            "originId" : "123",
                        }
                    ],
                    "type" : "Supplier"
                },
                {
                    "origin" : [
                        {
                            "originId" : "1233",
                        }
                    ],
                    "type" : "Supplier"
                }
            ]
        }
    ]
}

Want to replace data in orders (array) collaborators(array) with

**collaborators(array) ** data if matches originId of both

Expected output

{
  "_id" : "af5c00e4-d3a8-419d-8793-c0cf328802ec",
    "collaborators" : [
        {
            "_id" : "9bd2eee8-bf6c-4c6f-bab7-d2d175aed807",
            "origin" : [
                {
                    "originId" : "123"
                }
            ],
            "firstName" : "Parveen",
            "lastName" : "Vendor",
            "email" : "[email protected]"
        },
        {
            "_id" : "234324-bf6c-4c6f-bab7-d2d175aed807",
            "origin" : [
                {
                    "originId" : "1234"
                }
            ],
            "firstName" : "Parveen123",
            "lastName" : "34",
            "email" : "[email protected]"
        }
    ],
    "orders" : [
        {
            "totalAmount" : 10,
            "collaborators" : [
                {
                    "_id" : "9bd2eee8-bf6c-4c6f-bab7-d2d175aed807",
                    "origin" : [
                        {
                            "originId" : "123"
                        }
                    ],
                    "firstName" : "Parveen",
                    "lastName" : "Vendor",
                    "email" : "[email protected]"
                },
                {
                    "origin" : [
                        {
                            "originId" : "1233",
                        }
                    ],
                    "type" : "Supplier"
                }
            ]
        }
    ]
}

One collection record can have multiple collaborators , same as order can have multiple collaborators. Need to replace only where originId matches


Solution

  • One option is:

    1. Use $map, $mergeObjects and $filter to add a new key to each item of orders.collaborators with the matching item from collaborators if exists.
    2. choose the new key if it contains data or the original key, if not.
    db.collection.aggregate([
      {$set: {
          ordersCollaborators: {
            $map: {
              input: {$first: "$orders.collaborators"},
              in: {$mergeObjects: [
                  {original: "$$this"},
                  {new: {
                      $filter: {
                        input: "$collaborators",
                        as: "i",
                        cond: {
                          $eq: [
                            {$first: "$$i.origin.originId"},
                            {$first: "$$this.origin.originId"}
                          ]
                        }
                      }
                    }
                  }
                ]
              }
            }
          }
        }
      },
      {$set: {
          orders: [
            {totalAmount: {$first: "$orders.totalAmount"},
              collaborators: {
                $map: {
                  input: "$ordersCollaborators",
                  in: {
                    $cond: [
                      {$eq: [{$size: "$$this.new"}, 0]},
                      "$$this.original",
                      "$$this.new"
                    ]
                  }
                }
              }
            }
          ],
          ordersCollaborators: "$$REMOVE"
        }
      }
    ])
    

    See how it works on the playground example