Typescript Express中如何在findByIdAndUpdate内合并Mongoose文档的两个数组
实现方案
你之前写法失效的核心原因:普通的Mongoose更新操作无法直接引用文档自身的字段值,你写的'notifiedUsers'会被当作字符串常量处理,而非指向当前文档的notifiedUsers字段,同时也没有清空原notifiedUsers数组的逻辑,所以无法实现移动效果。
最优方案(MongoDB 4.2+ 支持,原子操作)
MongoDB 4.2及以上版本支持聚合管道式更新,可以在单次更新操作中引用文档现有字段,全程原子操作,无需额外查询,代码如下:
router.put('/delay/:id', async (req: Request, res: Response) => { try { const updatedEvent = await Event.findByIdAndUpdate( req.params.id, // 用数组包裹更新逻辑,代表使用聚合管道更新 [ { $set: { date: req.body.date, // 合并原有unnotifiedUsers和notifiedUsers的内容 // 不需要去重用$concatArrays,需要去重则替换为$setUnion unnotifiedUsers: { $concatArrays: ["$unnotifiedUsers", "$notifiedUsers"] }, // 清空已通知用户数组,完成移动操作 notifiedUsers: [] } } ], // 可选:返回更新后的文档用于校验 { new: true } ); if (!updatedEvent) { return res.status(404).json('事件不存在'); } res.status(200).json(`Event delayed to ${req.body.date}`); } catch (e: any) { console.log(e); res.status(500).json('更新失败:' + e.message); } });
低版本MongoDB兼容方案
如果你的MongoDB版本低于4.2,需要先查询文档再修改保存,代码如下:
router.put('/delay/:id', async (req: Request, res: Response) => { try { const event = await Event.findById(req.params.id); if (!event) { return res.status(404).json('事件不存在'); } // 移动数组内容 event.unnotifiedUsers.push(...event.notifiedUsers); // 可选:去重 // event.unnotifiedUsers = [...new Set(event.unnotifiedUsers.map(id => id.toString()))]; event.notifiedUsers = []; // 更新日期 event.date = req.body.date; await event.save(); res.status(200).json(`Event delayed to ${req.body.date}`); } catch (e: any) { console.log(e); res.status(500).json('更新失败:' + e.message); } });
内容的提问来源于stack exchange,提问作者Imran
相关产品推荐
相关产品推荐

