• mongodb 更新嵌套数组的值


    概要

    本文主要讲述在 mongodb 中,怎么更新嵌套数组的值。

     使用$更新数组

    1. 基本语法  { "<array>.$" : value } 
    2. 可以用于:update, findAndUpdate 等方法
    3. $是一个占位符一样的存在。代表被匹配的数组中的一个元素
    4. 可以匹配一个数组,匹配多个是会异常  index 0: 2 - Too many positional (i.e. '$') elements found in path ... ,即:只能在一层嵌套的数组中使用 $
    5. 示例 
      db.collection.update(
         { <array>: value ... },
         { <update operator>: { "<array>.$" : value } }
      )

     测试

    1.     创建一个测试数据
      for (let i = 0; i < 3; i++) {    
          let data = {
              name1_1: 'test' + i,
              arr_1: [{
                  a: i,
                  b: 2
              }, {
                  a: i + 1,
                  b: 2
              }]
          };
          db.nestedUpdate.insert(data);
      }
      创建数据脚本

      数据截图:

    2. 我想更新arr_1数组中,a = 1 的对象,更新为 {a:11,b:12} 运行更新代码,如下:
      db.nestedUpdate.updateMany({
          'arr_1.a': 1
      }, {
          $set: {
              'arr_1.$.a': 11,
              'arr_1.$.b': 12,
          }
      })

       运行后数据截图:

    3.   针对上述结构,更新 a= 11 的对象值(与上面不同,上面是更新对象里面的一个值),运行一下代码:
      db.nestedUpdate.updateMany({
          'arr_1.a': 11
      }, {
          $set: {
         'arr_1.$': {a:11, c:[1,2,3]}
      } })

      运行结果:

    4.  继续编辑,修改 arr_1.c 的元素,很容易想到如下:

      db.nestedUpdate.updateMany({
          'arr_1.c': 1
      }, {
          $set: {
              'arr_1.$.$': 11,
          }
      })

      然而,最终的运行结果却是: [Error] index 0: 2 - Too many positional (i.e. '$') elements found in path 'arr_1.$.$' 

       那么,我想更新数组中的数组下的一个元素这么办呢?下面介绍两种方法:1、遍历数组修改,2、使用 arrayFilter。个人推荐 arrayFilter 方式。

    .find.foreach + save (循环判断保存法)

    1. 通过 .find 找到满足条件的集合,(但只能找到根节点)
    2. 遍历需要修改的节点,修改其值,(先遍历arr_1, 在遍历 arr_1.c)
    3. 把修改完成的对象,通过 save 方法更新回数据库。
    4. 代码如下
      // 查找所有
      var all1 = db.nestedUpdate.find({});
      all1.forEach(function(it) {   
          var modified = false;
              // 遍历 arr_1
          for (var i = 0; i < it.arr_1.length; ++i) {
              var ac1 = it.arr_1[i];
              // 判断需要修改的
                      if (ac1.c && ac1.c.length > 0 && ac1.c[0] == 1) {
                  ac1.c[0] = 1111;
                  modified = true;
              }
          }
          
          if (modified) {
              db.nestedUpdate.save(it);
          }
      })

     利用arrayFilter

    • 基本语法
    db.collection.updateMany(
       { <query conditions> },
       { <update operator>: { "<array>.$[<identifier>]" : value } },
       { arrayFilters: [ { <identifier>: <condition> } ] }
    )

     注意

    • arrayFilter 数组中的顶级字段不能重复,如下:出现了两个 idx0,运行报错 index 0: 9 - Found multiple array filters with the same top-level field name idx0 
      db.nestedUpdate.updateMany({}, {
          $set: {
              'arr_1.$[idx0].c.$[idx1]': 1
          }
      }, {
          arrayFilters: [
              {
                  // idx0 满足条件: 需存在 c 字段
                  'idx0.c': {
                      $exists: true
                  },            
              },
              {
                  'idx0.a': 1,            
              },
              {
                  // idx1: 满足 值为 111
                  'idx1': 1111
              }
          ]
      });
      > [Error] index 0: 9 - Found multiple array filters with the same top-level field name idx0
        at line 1, column 1
      View Code
    • arrayFilter 中可以嵌套条件,如:
      db.nestedUpdate.updateMany({}, {
          $set: {
              'arr_1.$[idx0].c.$[idx1]': 1
          }
      }, {
          arrayFilters: [
              {
                  // idx0 满足条件: 需存在 c 字段
                  'idx0.c': {
                      $exists: true
                  },
                  'idx0.a': 1,
              },
              {
                  // idx1: 满足 值为 111
                  'idx1': 1111
              }
          ]
      });
      
      // 或
      
      db.nestedUpdate.updateMany({}, {
          $set: {
              'arr_1.$[idx0].c.$[idx1]': 1
          }
      }, {
          arrayFilters: [
              {
                  // idx0 满足条件: 需存在 c 字段
                  idx0: {
                      c: {
                          $exists: true
                      },
                      a: 1
                  }
              },
              {
                  // idx1: 满足 值为 111
                  'idx1': 1111
              }
          ]
      });
      View Code
    • arrayFilter 必须包含所有的索引的条件。否则出现错误 [Error] index 0: 2 - No array filter found for identifier 'idx2' in path 'arr_1.$[].arr_1_1.$[idx1].arr1_1_1.$[idx2]' 
      db.nestedUpdate1.updateMany({}, {
          $set: {
              'arr_1.$[].arr_1_1.$[idx1].arr1_1_1.$[idx2]': null
          }
      }, {
          arrayFilters: [
              {
                  // idx1: 满足 name <= 1
                  'idx1.name': {
                      $lte: 1
                  }
              },
              
          ]
      })
      > [Error] index 0: 2 - No array filter found for identifier 'idx2' in path 'arr_1.$[].arr_1_1.$[idx1].arr1_1_1.$[idx2]'
        at line 1, column 1
      > 时间: 0.003s
      完整代码
    • $[idx] 中的idx 可以自定义名字,只需要arrayFilter中名字一样就可以,如 $[i], $[j]
    • 不止updateMany可以用,update、findAndUpdate、findAndModify 等也可以用
    • 可以与$[] 一起使用,需保证数组中的所有元素都满足后面的条件,如:
      db.nestedUpdate1.updateMany({}, {
          $set: {
              'arr_1.$[].arr_1_1.$[idx1].arr1_1_1.$[idx2]': null
          }
      }, {
          arrayFilters: [
              {
                  // idx1: 满足 name <= 1
                  'idx1.name': {
                      $lte: 1
                  }
              },
              {
                  idx2: 1
              }
          ]
      })

      运行示意:

  • 相关阅读:
    静态成员 执行顺序
    排序之插入排序
    结构体字节对齐问题
    建模基础&UML
    C#中隐藏(new)和方法重载(overide)的区别
    培训记录
    C笔记
    用例
    .NET架构
    C#格式化日期
  • 原文地址:https://www.cnblogs.com/zhongchengyi/p/12162792.html
Copyright © 2020-2023  润新知