Mongoose中$push更新嵌套数组时覆盖friends字段原因咨询
问题根本原因
第一种写法覆盖friends下其他字段的核心原因是不符合MongoDB更新操作的语法规则:
- MongoDB的更新操作符(比如
$push、$set)必须作为更新参数的顶层键存在,才会被识别为操作指令。 - 你之前的写法把
$push放在了friends字段的值对象内部,MongoDB不会识别这是更新操作,反而会判定你要全量替换整个friends字段的值,把friends直接覆盖成你传入的{ $push: { pending: xxx } }对象,原本friends下的active数组、pending数组的历史数据自然会被全部擦除。
$push操作符的正确用法
操作嵌套在对象里的数组字段时,需要使用点路径语法直接定位到目标数组,把$push作为更新参数的顶层键,路径用引号包裹即可,不会影响同层级的其他字段数据。
修正后的实现代码如下:
sendFriendRequest: async (parent, { username }, context) => { console.log(context.user.username); if (context.user) { // 向好友接收方的待处理列表追加发起方用户名 await User.findOneAndUpdate( { username }, { $push: { "friends.pending": context.user.username } } ); // 向好友发起方的待处理列表追加接收方用户名 await User.findOneAndUpdate( { username: context.user.username }, { $push: { "friends.pending": username } } ); } }
这种写法相比你临时用的findOne+原生push+save方案是原子操作,并发场景下不会出现读取旧值导致的写入覆盖问题,同时减少了数据库交互次数,性能更稳定,执行后friends.active下的原有数据会完整保留,不会被覆盖。
内容的提问来源于stack exchange,提问作者Blake McCarty
相关产品推荐
相关产品推荐

