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

    運行示意:

     

     


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM