欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

mongodb 更新嵌套数组的值

程序员文章站 2022-06-04 17:54:39
概要 本文主要讲述在 mongodb 中,怎么更新嵌套数组的值。 使用$更新数组 测试 for (let i = 0; i < 3; i++) { let data = { name1_1: 'test' + i, arr_1: [{ a: i, b: 2 }, { a: i + 1, b: 2 } ......

概要

本文主要讲述在 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);
    }

    数据截图:

    mongodb 更新嵌套数组的值

     

  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,
        }
    })

     运行后数据截图:

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

    运行结果:

    mongodb 更新嵌套数组的值

     

  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);
        }
    })

    mongodb 更新嵌套数组的值

 利用arrayfilter

  • 基本语法
db.collection.updatemany(
   { <query conditions> },
   { <update operator>: { "<array>.$[<identifier>]" : value } },
   { arrayfilters: [ { <identifier>: <condition> } ] }
)
    • 官方文档地址:
    •  如上,建立一个示例,把 arr_1.c的值改回去mongodb 更新嵌套数组的值

       

       

 注意

  • 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
  • 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
            }
        ]
    });
  • 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
            }
        ]
    })

    运行示意:mongodb 更新嵌套数组的值