Mongoose实现数组内对象存在则更新、不存在则新增的操作方法
Mongoose Streak集合当日记录更新实现方案
需求说明
在streaks数组中查询是否存在日期为当日的对象:
- 存在则直接累加
questionCount字段的数值 - 不存在则新建一条包含当日日期的对象
集合结构定义
const mongoose = require('mongoose'); const streakSchema = new mongoose.Schema({ _id: { type: mongoose.Types.ObjectId, ref: "User", }, streaks: [{ date: { type: Date, required: true }, questionCount: { type: Number, required: true, default: 0 } }] }); const Streak = mongoose.model('Streak', streakSchema);
实现代码
前置日期处理
MongoDB的Date类型存储精度到毫秒,需要先将当日日期的时分秒清零,避免匹配失败:
// 构造当日零点的日期对象 const today = new Date(); today.setHours(0, 0, 0, 0); // 要更新的对应用户ID const targetUserId = mongoose.Types.ObjectId('你的用户ID字符串'); // 本次要累加的题目数量 const incrementCount = 1;
核心更新逻辑
使用Mongoose聚合管道更新,单次数据库请求完成操作,避免并发读写冲突:
await Streak.updateOne( { _id: targetUserId }, [ { $set: { streaks: { $cond: { // 判断streaks数组中是否存在当日记录 if: { $in: [today, "$streaks.date"] }, // 存在则累加对应记录的questionCount then: { $map: { input: "$streaks", in: { $cond: [ { $eq: ["$$this.date", today] }, { $mergeObjects: [ "$$this", { questionCount: { $add: ["$$this.questionCount", incrementCount] } } ] }, "$$this" ] } } }, // 不存在则新增当日记录 else: { $concatArrays: [ "$streaks", [{ date: today, questionCount: incrementCount }] ] } } } } } ], // 可选配置:如果对应用户的streak文档不存在则自动创建 { upsert: true } );
注意事项
- 必须清零日期的时分秒,否则不同时间生成的日期对象会因为毫秒数不同无法匹配
- 聚合管道更新无需先查询再修改,性能更高,同时避免并发场景下的读写冲突
- 不需要自动创建用户streak文档时,删除
upsert: true参数即可
内容的提问来源于stack exchange,提问作者NIKHILKUMAR SINGH
相关产品推荐
相关产品推荐

