Home > Mobile >  Update certain fields only when current value is undefined with Mongoose
Update certain fields only when current value is undefined with Mongoose

Time:09-21

If a user deactivates their account we need to perform some updates to different collections. One of these collections is adding an end_date to their mandate and set a stop reason to the assigned EANs (it's a code for an energy meter) which do not have a stop reason already.

Is it possible to do this update in one call?

The current call looks like this but the end_date and stop_reason of the assigned_eans inside the tariffs object may not be updated when a value is already set.

await EnergyMandate.updateMany([{ leadID, end_date: { $exists: false } }, {
    $set: { 
        end_date: Math.floor(Date.now()),
        stop_reason: 'deactivated_account',

        'tariffs.electricity.assigned_eans.$[].end_date': Math.floor(Date.now()),
        'tariffs.electricity.assigned_eans.$[].stop_reason': 'deactivated_account',
    
        'tariffs.gas.assigned_eans.$[].end_date': Math.floor(Date.now()),
        'tariffs.gas.assigned_eans.$[].stop_reason': 'deactivated_account',
    }
}], { session });

[EDIT 1] Updated query based on @nimrod serok's answer

const mandates = await EnergyMandate.updateMany({ leadID, end_date: { $exists: false } }, {
    $set: {
        end_date: Math.floor(Date.now()),
        stop_reason: 'deactivated_account',

        'tariffs.electricity.assigned_eans': {
            $map: {
                input: "$tariffs.electricity.assigned_eans",
                in: {   
                    $mergeObjects: [
                        "$$this",
                        {
                            end_date: { $ifNull: ["$$this.end_date", Math.floor(Date.now())] },
                            stop_reason: { $ifNull: ["$$this.stop_reason", 'deactivated_account'] }
                        }
                    ]
                }
            }
        },

        'tariffs.gas.assigned_eans': {
            $map: {
                input: "$tariffs.gas.assigned_eans",
                in: {   
                    $mergeObjects: [
                        "$$this",
                        {
                            end_date: { $ifNull: ["$$this.end_date", Math.floor(Date.now())] },
                            stop_reason: { $ifNull: ["$$this.stop_reason", 'deactivated_account'] }
                        }
                    ]
                }
            }
        }
    }
});

CodePudding user response:

If I understand correctly you can use update pipeline with $map and $ifNull for this:

db.collection.updateMany(
  {leadID, end_date: {$exists: false}},
  [{$set: {
      end_date: ISODate("2022-09-20T18:00:00.000Z"),
      stop_reason: "deactivated_account",
      "tariffs.electricity.assigned_eans": {
        $map: {
          input: "$tariffs.electricity.assigned_eans",
          in: {
            end_date: {$ifNull: [
                {$cond: [
                    {$eq: ["$$this.end_date", ""]},
                    ISODate("2022-09-20T18:00:00.000Z"),
                    "$$this.end_date"
                ]}, ISODate("2022-09-20T18:00:00.000Z")
            ]},
            stop_reason: {$ifNull: [
                {$cond: [
                    {$eq: ["$$this.stop_reason", ""]},
                    "deactivated_account",
                    "$$this.stop_reason"
                  ]}, "deactivated_account"]}
          }
        }
      },
      "tariffs.gas.assigned_eans": {
        $map: {
          input: "$tariffs.gas.assigned_eans",
          in: {
            end_date: {$ifNull: [
                {$cond: [
                    {$eq: ["$$this.end_date", ""]}, 
                     ISODate("2022-09-20T18:00:00.000Z"),
                     "$$this.end_date"
                ]}, ISODate("2022-09-20T18:00:00.000Z")
            ]},
            stop_reason: {$ifNull: [
                {$cond: [
                    {$eq: ["$$this.stop_reason", ""]},
                    "deactivated_account",
                    "$$this.stop_reason"
                ]}, "deactivated_account"
              ]}
          }
        }
      }
    }
  }
])

See how it works on the playground example

  • Related