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

Mongoose数组对象插入或更新?遇重复键错误求助

问题根源分析

你遇到的重复键错误,核心原因是Schema中给数组元素的Index和Name设置的unique: true是集合级别的全局唯一约束,而非同一个Client下的数组内部唯一。这意味着整个telemetries集合里,所有文档的MQTT_FIELD数组中的Index都不能重复,哪怕属于不同Client的文档。另外,你当前的findOneAndUpdate逻辑只能处理插入场景,无法覆盖更新已存在元素的情况,触发upsert时容易违反全局唯一约束。

解决方案

步骤1:修正Schema与索引

先删除数组元素上的全局唯一约束,改为创建复合唯一索引,确保同一个Client下的MQTT_FIELD.Index唯一:

const TelemetrySchema = new mongoose.Schema({
  Client: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Client',
  },
  MQTT_FIELD: [
    {
      _id: false,
      Index: {
        type: Number,
        required: true,
        // 移除全局unique约束
      },
      Name: {
        type: String,
        trim: true,
        required: true,
        // 若不需要全局唯一Name,同样移除该约束
      },
    },
  ],
});

// 创建复合唯一索引:同一个Client下,MQTT_FIELD.Index不能重复
TelemetrySchema.index({ Client: 1, 'MQTT_FIELD.Index': 1 }, { unique: true });

步骤2:实现“插入/更新”逻辑

方案一:分两次操作(兼容性好)

先尝试更新已存在的元素,若未找到则执行插入:

const { Client, Field } = req.body;

// 先尝试更新已存在的元素
let telemetry = await Telemetry.findOneAndUpdate(
  { Client, 'MQTT_FIELD.Index': Field.Index },
  { $set: { 'MQTT_FIELD.$.Name': Field.Name } },
  { new: true, omitUndefined: true }
).exec();

// 若未找到匹配项,执行插入(或upsert创建新文档)
if (!telemetry) {
  telemetry = await Telemetry.findOneAndUpdate(
    { Client },
    { $addToSet: { MQTT_FIELD: Field } },
    { upsert: true, new: true, omitUndefined: true }
  ).exec();
}

return res.status(200).json(telemetry);

方案二:聚合管道更新(MongoDB 4.2+支持,一次操作完成)

利用聚合管道的条件判断,一次操作实现“存在则更新,不存在则添加”:

const { Client, Field } = req.body;

const telemetry = await Telemetry.findOneAndUpdate(
  { Client },
  [
    {
      $set: {
        MQTT_FIELD: {
          $cond: [
            // 判断数组中是否存在目标Index
            { $in: [Field.Index, '$MQTT_FIELD.Index'] },
            // 存在则更新对应元素的Name
            {
              $map: {
                input: '$MQTT_FIELD',
                as: 'field',
                in: {
                  $mergeObjects: [
                    '$$field',
                    {
                      $cond: [
                        { $eq: ['$$field.Index', Field.Index] },
                        { Name: Field.Name },
                        {}
                      ]
                    }
                  ]
                }
              }
            },
            // 不存在则追加新元素到数组
            { $concatArrays: ['$MQTT_FIELD', [Field]] }
          ]
        }
      }
    }
  ],
  { upsert: true, new: true, omitUndefined: true }
).exec();

return res.status(200).json(telemetry);

内容的提问来源于stack exchange,提问作者MeerArtefakt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 08:15:46