Mongoose更新文档内指定域名状态时误覆盖其他域名条目问题
问题原因
- 你当前使用的
findByIdAndUpdate方法第一个参数仅接收文档ID,你传入的额外domain: args.domain过滤条件不会生效,无法定位到数组内对应域名的条目 - 你直接对
preferences.domain.status字段赋值对象,相当于直接把整个状态数组替换为单个对象,自然会覆盖其他所有域名的记录 - 要更新数组内匹配的单个元素,需要使用MongoDB的数组占位符
$,配合查询条件中的数组元素匹配规则才能实现精准更新
适配原有逻辑的修复代码
if (Boolean(checkStat) === true) { // 改用findOneAndUpdate,查询条件同时匹配用户ID和数组内对应域名的条目 await userModel.findOneAndUpdate( { _id: ctx.userId, "preferences.domain.status.domain": args.domain }, { // 用$占位符指代查询条件匹配到的那个数组元素,仅更新该元素的status字段 "preferences.domain.status.$.status": args.status } ); return { message: "sucessfully updated status of " + args.domain + " to " + args.status, }; } else { // 新增逻辑保持不变即可 await userModel.findByIdAndUpdate( ctx.userId, { $push: { ["preferences.domain.status"]: { domain: args.domain, status: args.status, }, }, }, { upsert: true, new: true, } ); return { message: "sucessfully set status of " + args.domain + " to " + args.status, }; }
可选优化方案(无需提前查询校验,单语句实现更新/插入)
如果你的MongoDB版本 >= 4.2,可以直接使用带聚合管道的更新语句,不用提前判断域名是否存在,减少一次数据库查询:
await userModel.findByIdAndUpdate( ctx.userId, [ { $set: { "preferences.domain.status": { $cond: { if: { $in: [args.domain, "$preferences.domain.status.domain"] }, then: { $map: { input: "$preferences.domain.status", in: { $mergeObjects: [ "$$this", { $cond: [{ $eq: ["$$this.domain", args.domain] }, { status: args.status }, {}] } ] } } }, else: { $concatArrays: [ "$preferences.domain.status", [{ domain: args.domain, status: args.status }] ] } } } } } ], { upsert: true, new: true } )
内容的提问来源于stack exchange,提问作者user16009119
相关产品推荐
相关产品推荐

