Mongoose操作MongoDB如何更新子文档,无匹配时新建对应文档?
问题根源
你当前的代码存在3个核心问题,直接导致报错和逻辑不符合预期:
- 查询逻辑错误:你写的
members : [{_id: user.id}]是匹配members数组完全等于只有该用户对象的文档,不是匹配数组中存在对应_id用户的文档 - 更新逻辑错误:直接给
members赋值对象会直接覆盖整个members数组,而不是修改/新增数组成员 - Schema定义错误:
userSchema上加了全局{unique: true}配置,会要求整个集合中所有用户子文档的_id全局唯一,只要第二个父文档出现相同用户ID就会报重复键错误,和你要的同个服务器下用户ID唯一的需求完全不符
修正方案
第一步:修正Schema定义
const mongoose = require('mongoose') const reqString = { type: String, required: true } // 移除子文档全局unique配置 const userSchema = mongoose.Schema({ _id: reqString, bot: Boolean, commandUsed: Boolean }) const commandUseSchema = mongoose.Schema({ _id: reqString, members: [userSchema] }) module.exports = mongoose.model('command-usage-checker', commandUseSchema)
第二步:修正更新逻辑
用Mongoose数组运算符实现「存在则更新、不存在则插入」的原子操作,同时避免混用await和回调导致的逻辑混乱:
// 先尝试更新已存在的对应用户记录 const updateExisting = await commandUsageSchema.findOneAndUpdate( { _id: guild.id, "members._id": user.id // 匹配当前服务器下存在该用户的记录 }, { // 用$占位符定位到匹配的数组成员,更新对应字段 $set: { "members.$.bot": user.bot, "members.$.commandUsed": true } }, { new: true } ) // 没有匹配到已存在用户,就将新用户推入数组 if (!updateExisting) { await commandUsageSchema.findOneAndUpdate( { _id: guild.id }, { // $addToSet会自动判断元素是否存在,避免重复插入 $addToSet: { members: { _id: user.id, bot: user.bot, commandUsed: true } } }, // 当前服务器没有记录就自动新建 { upsert: true, new: true } ) }
额外说明
如果需要保证同一个服务器下用户ID唯一,可以在commandUseSchema上给members._id加复合唯一索引,避免同个服务器出现重复用户记录。
内容的提问来源于stack exchange,提问作者MrHan Brolo
相关产品推荐
相关产品推荐

