概要
本文主要講述在 mongodb 中,怎么更新嵌套陣列的值,

使用$更新陣列
- 基本語法 { "<array>.$" : value }
- 可以用于:update, findAndUpdate 等方法
- $是一個占位符一樣的存在,代表被匹配的陣列中的一個元素
- 可以匹配一個陣列,匹配多個是會例外 index 0: 2 - Too many positional (i.e. '$') elements found in path ... ,即:只能在一層嵌套的陣列中使用 $
- 示例
db.collection.update( { <array>: value ... }, { <update operator>: { "<array>.$" : value } })
測驗
- 創建一個測驗資料

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);}
創建資料腳本資料截圖:

- 我想更新arr_1陣列中,a = 1 的物件,更新為 {a:11,b:12} 運行更新代碼,如下:
db.nestedUpdate.updateMany({ 'arr_1.a': 1}, { $set: { 'arr_1.$.a': 11, 'arr_1.$.b': 12, }})
運行后資料截圖:

- 針對上述結構,更新 a= 11 的物件值(與上面不同,上面是更新物件里面的一個值),運行一下代碼:
db.nestedUpdate.updateMany({ 'arr_1.a': 11}, { $set: {
'arr_1.$': {a:11, c:[1,2,3]}
} })運行結果:

繼續編輯,修改 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 (回圈判斷保存法)
- 通過 .find 找到滿足條件的集合,(但只能找到根節點)
- 遍歷需要修改的節點,修改其值,(先遍歷arr_1, 在遍歷 arr_1.c)
- 把修改完成的物件,通過 save 方法更新回資料庫,
- 代碼如下
// 查找所有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> } ] })
- 官方檔案地址:https://docs.mongodb.com/manual/reference/operator/update-array/
如上,建立一個示例,把 arr_1.c的值改回去

注意
- 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 } ]})
運行示意:

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/26271.html
標籤:NoSQL

