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

MongoDB findAndModify更新contexts对象失败,求排查与修正

MongoDB批量更新脚本问题排查

集合结构

{
  '_id': objectId,
  'uuid': string,
  'contexts' object -> (0:"wifi6", 1:"anydesk", _seriablizable_class:"App\\Collection\\Context")
}

实际文档示例

{
  "_id": {
    "$oid": "6399a76340573591210b9cf3"
  },
  "uuid": "ae7470a9-af8f-4baf-9981-1581313e3923",
  "name": "text",
  "description": "text",
  "device_info": {},
  "contexts": {
    "0": "wifi6",
    "1": "4g",
    "2": "2.4",
    "_seriablizable_class": "App\\Device\\Domain\\ValueObject\\ContextCollection"
  },
  "filter_contexts": [
    "wifi6",
    "4g",
    "2.4"
  ],
  "deleted": false,
  "created_at": {
    "$date": {
      "$numberLong": "1671014243165"
    }
  },
  "updated_at": {
    "$date": {
      "$numberLong": "1671014243166"
    }
  }
}

预期更新后文档

{
  "_id": {
    "$oid": "6399a76340573591210b9cf3"
  },
  "uuid": "ae7470a9-af8f-4baf-9981-1581313e3923",
  "name": "text",
  "description": "text",
  "device_info": {},
  "contexts": {
    "0": "wifi6",
    "1": "4g",
    "2": "2.4",
    "3": "5G",
    "_seriablizable_class": "App\\Device\\Domain\\ValueObject\\ContextCollection"
  },
  "filter_contexts": [
    "wifi6",
    "4g",
    "2.4",
    "5G"
  ],
  "deleted": false,
  "created_at": {
    "$date": {
      "$numberLong": "1671014243165"
    }
  },
  "updated_at": {
    "$date": {
      "$numberLong": "1671014243166"
    }
  }
}

需求描述

批量更新集合中所有包含contexts.wifi6的文档:

  • 在contexts对象中,按现有数字索引的数量(排除_seriablizable_class字段)添加新字段,键为对应数字、值为"5G"
  • 同时更新filter_contexts数组,追加"5G"元素

问题脚本(未生效)

db.devices.findAndModify(
{'query':{contexts:"Wifi6"},
 'update': {
   [
     '$group': {
        "_id": "$_id",
        "count": {
            "$sum": { 
                "$size": { "$objectToArray": "$contexts" }
            }
        },
        contexts: {$first:'$contexts'}
    },
    '$set': { 'contexts':
       { $mergeObjects: [ { "$count-1": "5G"}, "$contexts" ] }
    }
   ]
 }
})

脚本问题分析

  • 查询条件错误:原查询{contexts:"Wifi6"}是匹配整个contexts对象等于字符串"Wifi6",实际需要匹配contexts中存在值为wifi6的字段(注意大小写,原数据是小写),且匹配逻辑错误。
  • API使用错误:findAndModify的update参数仅支持标准更新操作符(如$set、$push),不能直接传入聚合管道阶段($group是聚合阶段,无法在update中执行)。
  • 计数逻辑错误:$size: {$objectToArray: "$contexts"}会包含_seriablizable_class字段,导致计数包含非数字键;且单个文档无需用$sum求和。
  • 动态键名生成错误:{ "$count-1": "5G"}无法被MongoDB解析为动态键名,需要用$arrayToObject配合计算逻辑生成键值对。

正确解决方案

使用updateMany配合聚合管道实现动态更新,脚本如下:

db.devices.updateMany(
  // 查询条件:匹配contexts中包含值为wifi6的文档
  { "contexts": { "$elemMatch": { "$eq": "wifi6" } } },
  [
    {
      $set: {
        // 合并原contexts与新生成的5G字段
        contexts: {
          $mergeObjects: [
            "$contexts",
            {
              $arrayToObject: [
                [
                  {
                    // 计算新键名:数字键的数量转为字符串
                    k: {
                      $toString: {
                        $size: {
                          $filter: {
                            input: { $objectToArray: "$contexts" },
                            // 过滤出键为纯数字的元素
                            cond: { $regexMatch: { input: "$$this.k", regex: "^\\d+$" } }
                          }
                        }
                      },
                    },
                    v: "5G"
                  }
                ]
              ]
            }
          ]
        },
        // 追加5G到filter_contexts数组
        filter_contexts: { $concatArrays: ["$filter_contexts", ["5G"]] },
        // 更新updated_at为当前时间(可选)
        updated_at: new Date()
      }
    }
  ]
)

脚本说明

  1. 查询逻辑:通过$elemMatch匹配contexts对象中的值包含wifi6,确保仅更新符合条件的文档。
  2. 动态键生成:
    • $objectToArray将contexts转为键值对数组
    • $filter筛选出键为纯数字的元素
    • $size获取数字键的数量,作为新字段的键名(转为字符串)
    • $arrayToObject将键值对转为对象,再通过$mergeObjects合并到原contexts中
  3. 数组更新:用$concatArrays将"5G"追加到filter_contexts数组末尾
  4. 时间更新:可选将updated_at设为当前时间,符合业务更新逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 13:55:36