You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mongoose操作MongoDB如何更新子文档,无匹配时新建对应文档?

问题根源

你当前的代码存在3个核心问题,直接导致报错和逻辑不符合预期:

  1. 查询逻辑错误:你写的members : [{_id: user.id}]是匹配members数组完全等于只有该用户对象的文档,不是匹配数组中存在对应_id用户的文档
  2. 更新逻辑错误:直接给members赋值对象会直接覆盖整个members数组,而不是修改/新增数组成员
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.15 13:15:07