如何避免MongoDB文档内对象数组出现重复元素
MongoDB score数组重复问题解决方案
问题根因
MongoDB的$addToSet运算符是基于元素完整内容判断是否重复的:
- 首次执行插入时,你插入的是仅包含
_id: matchID的空结构对象 - 后续你更新该对象补充了runsScored等业务字段后,该对象的完整内容已经发生变化
- 再次执行插入语句时,
$addToSet认为新的{_id: matchID}对象和已存在的带业务数据的对象不是同一个元素,就会重复插入,最终出现你遇到的重复问题。
解决方案1:无聚合简单方案(推荐初学者使用)
仅需要在原有更新语句的查询条件中增加判断逻辑:只有score数组中不存在对应matchID的元素时,才执行插入操作,就算代码重复执行也不会产生重复数据:
await Scorecard.findOneAndUpdate( { _id: fielder.player_id, // 新增条件:score数组不存在_id等于matchID的元素时才执行更新 "score._id": { $ne: matchID } }, { $addToSet: { "score": { _id: matchID } } } );
解决方案2:清理现有重复脏数据
如果当前数据库中已经存在大量重复项,可以执行以下更新操作按matchID去重,每个_id仅保留第一条带业务数据的元素,自动删除后续新增的全字段为0的重复项:
await Scorecard.updateMany( {}, [ { $set: { score: { $reduce: { input: "$score", initialValue: [], in: { $cond: [ { $in: ["$$this._id", "$$value._id"] }, "$$value", { $concatArrays: ["$$value", ["$$this"]] } ] } } } } } ] )
后续更新单条score数据的正确写法
后续需要补充对应matchID的业务数据时,使用 positional operator $ 精准定位元素更新,避免写错数据:
await Scorecard.findOneAndUpdate( { _id: fielder.player_id, "score._id": matchID }, { $set: { "score.$.runsScored": 21, "score.$.ballFaced": 10, // 其他需要更新的业务字段 } } )
内容的提问来源于stack exchange,提问作者Muhammad Danyal
相关产品推荐
相关产品推荐

