Mongoose仅未定义字段更新:账户停用后的批量数据更新问询
如何通过单次MongoDB调用完成账户停用后的多字段条件更新?
当用户停用账户时,需要执行两类更新操作:
- 为用户的mandate添加
end_date字段 - 为未设置
stop_reason的已分配EAN(电表编码)补充该字段,同时确保已有end_date或stop_reason的EAN不被覆盖
原代码的问题
你最初的updateMany调用会强制覆盖所有assigned_eans数组元素的end_date和stop_reason,不管这些字段原本是否已有值,不符合"仅更新未设置字段"的需求:
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 });
优化后的单次调用方案
通过$map结合$mergeObjects和$ifNull,可以实现单次调用完成条件更新,仅对未设置的字段赋值,保留已有值:
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'] } } ] } } } } });
核心逻辑说明
$map:遍历assigned_eans数组的每个元素$mergeObjects:将原元素的所有字段与新的条件赋值字段合并,原字段会被保留,仅补充未设置的字段$ifNull:判断目标字段是否为空/不存在,若为空则使用新值,否则保留原字段值
内容的提问来源于stack exchange,提问作者Thore
相关产品推荐
相关产品推荐

