蔡陆 發表於 2020-1-9 16:05:00

mongodb 更新嵌套数组的值

<h2>概要</h2>
<p>本文主要讲述在 mongodb 中,怎么更新嵌套数组的值。</p>
<p><img src="https://img2018.cnblogs.com/blog/625732/202001/625732-20200107171023630-278468092.png" alt=""></p>
<h2>&nbsp;使用$更新数组</h2>
<ol>
<li>基本语法&nbsp;&nbsp;<span class="cnblogs_code">{ <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">&lt;array&gt;.$</span><span style="color: rgba(128, 0, 0, 1)">"</span> : value }</span>&nbsp;</li>
<li>可以用于:update, findAndUpdate 等方法</li>
<li>$是一个占位符一样的存在。代表被匹配的数组中的一个元素</li>
<li>可以匹配一个数组,匹配多个是会异常&nbsp;<span class="cnblogs_code"> index 0: 2 - Too many positional (i.e. '$') elements found <span style="color: rgba(0, 0, 255, 1)">in</span> path ...</span>&nbsp;,即:只能在一层嵌套的数组中使用 $</li>
<li>示例&nbsp;
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">db.collection.update(
   { &lt;array</span>&gt;<span style="color: rgba(0, 0, 0, 1)">: value ... },
   { &lt;update operator</span>&gt;: { <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">&lt;array&gt;.$</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : value } }
)</span></pre>
</div>
<p>&nbsp;</p>
</li>
</ol>
<h3>&nbsp;测试</h3>
<ol>
<li>    创建一个测试数据
<div class="cnblogs_code"><img id="code_img_closed_9e85f793-0317-4f7a-9964-d034ba4310e8" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_9e85f793-0317-4f7a-9964-d034ba4310e8" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_9e85f793-0317-4f7a-9964-d034ba4310e8" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 0; i &lt; 3; i++<span style="color: rgba(0, 0, 0, 1)">) {   
    let data </span>=<span style="color: rgba(0, 0, 0, 1)"> {
      name1_1: 'test' </span>+<span style="color: rgba(0, 0, 0, 1)"> i,
      arr_1: [{
            a: i,
            b: </span>2<span style="color: rgba(0, 0, 0, 1)">
      }, {
            a: i </span>+ 1<span style="color: rgba(0, 0, 0, 1)">,
            b: </span>2<span style="color: rgba(0, 0, 0, 1)">
      }]
    };
    db.nestedUpdate.insert(data);
}</span></pre>
</div>
<span class="cnblogs_code_collapse">创建数据脚本</span></div>
<p>数据截图:</p>
<p><img src="https://img2018.cnblogs.com/blog/625732/202001/625732-20200107175116720-1080872829.png" alt="" width="612" height="584"></p>
<p>&nbsp;</p>
</li>
<li>我想更新arr_1数组中,a = 1 的对象,更新为 {a:11,b:12} 运行更新代码,如下:
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">db.nestedUpdate.updateMany({
    'arr_1.a': </span>1<span style="color: rgba(0, 0, 0, 1)">
}, {
    </span><span style="color: rgba(128, 0, 128, 1)">$set</span><span style="color: rgba(0, 0, 0, 1)">: {
      'arr_1.</span>$.a': 11<span style="color: rgba(0, 0, 0, 1)">,
      'arr_1.</span>$.b': 12<span style="color: rgba(0, 0, 0, 1)">,
    }
})</span></pre>
</div>
<p>&nbsp;运行后数据截图:</p>
<img src="https://img2018.cnblogs.com/blog/625732/202001/625732-20200107175557722-1196741413.png" alt="" width="410" height="549"></li>
<li>  针对上述结构,更新 a= 11 的对象值(与上面不同,上面是更新对象里面的一个值),运行一下代码:
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">db.nestedUpdate.updateMany({
    'arr_1.a': </span>11<span style="color: rgba(0, 0, 0, 1)">
}, {
    </span><span style="color: rgba(128, 0, 128, 1)">$set</span><span style="color: rgba(0, 0, 0, 1)">: {<br></span>     'arr_1.$': {a:11, c:}<br> } })</pre>
</div>
<p>运行结果:</p>
<img src="https://img2018.cnblogs.com/blog/625732/202001/625732-20200107180253942-748883866.png" alt="" width="499" height="497">
<p>&nbsp;</p>
</li>
<li>
<p>&nbsp;继续编辑,修改 arr_1.c 的元素,很容易想到如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">db.nestedUpdate.updateMany({
    'arr_1.c': </span>1<span style="color: rgba(0, 0, 0, 1)">
}, {
    </span><span style="color: rgba(128, 0, 128, 1)">$set</span><span style="color: rgba(0, 0, 0, 1)">: {
      'arr_1.</span>$.$': 11<span style="color: rgba(0, 0, 0, 1)">,
    }
})</span></pre>
</div>
<p>然而,最终的运行结果却是:&nbsp;<span class="cnblogs_code"> index 0: 2 - Too many positional (i.e. '$') elements found <span style="color: rgba(0, 0, 255, 1)">in</span> path 'arr_1.$.$'</span>&nbsp;</p>
<p>&nbsp;那么,我想更新数组中的数组下的一个元素这么办呢?下面介绍两种方法:1、遍历数组修改,2、使用 arrayFilter。个人推荐 <span style="color: rgba(255, 0, 0, 1)">arrayFilter&nbsp;</span>方式。</p>
</li>
</ol>
<h2>.find.foreach + save (循环判断保存法)</h2>
<ol>
<li>通过 .find 找到满足条件的集合,(但只能找到根节点)</li>
<li>遍历需要修改的节点,修改其值,(先遍历arr_1, 在遍历 arr_1.c)</li>
<li>把修改完成的对象,通过 save 方法更新回数据库。</li>
<li>代码如下
<div class="cnblogs_code">
<pre>//<span style="color: rgba(0, 0, 0, 1)"> 查找所有
var all1 </span>=<span style="color: rgba(0, 0, 0, 1)"> db.nestedUpdate.find({});
all1.</span><span style="color: rgba(0, 0, 255, 1)">forEach</span>(<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(it) {   
    var modified </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
      </span>//<span style="color: rgba(0, 0, 0, 1)"> 遍历 arr_1
    </span><span style="color: rgba(0, 0, 255, 1)">for</span> (var i = 0; i &lt; it.arr_1.length; ++<span style="color: rgba(0, 0, 0, 1)">i) {
      var ac1 </span>=<span style="color: rgba(0, 0, 0, 1)"> it.arr_1;
      </span>//<span style="color: rgba(0, 0, 0, 1)"> 判断需要修改的
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (ac1.c &amp;&amp; ac1.c.length &gt; 0 &amp;&amp; ac1.c == 1<span style="color: rgba(0, 0, 0, 1)">) {
            ac1.c[</span>0] = 1111<span style="color: rgba(0, 0, 0, 1)">;
            modified </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
      }
    }
   
    </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (modified) {
      db.nestedUpdate.save(it);
    }
})</span></pre>
</div>
<p><img src="https://img2018.cnblogs.com/blog/625732/202001/625732-20200109144129197-512772084.png" alt=""></p>
</li>
</ol>
<h2>&nbsp;利用arrayFilter</h2>
<ul>
<li>基本语法</li>
</ul>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">db.collection.updateMany(
   { &lt;query conditions</span>&gt;<span style="color: rgba(0, 0, 0, 1)"> },
   { &lt;update operator</span>&gt;: { <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">&lt;array&gt;.$[&lt;identifier&gt;]</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : value } },
   { arrayFilters: [ { &lt;identifier</span>&gt;: &lt;condition&gt;<span style="color: rgba(0, 0, 0, 1)"> } ] }
)</span></pre>
</div>
<ul>
<ul>
<li>官方文档地址:https://docs.mongodb.com/manual/reference/operator/update-array/</li>
<li>
<p>&nbsp;如上,建立一个示例,把 arr_1.c的值改回去<img src="https://img2018.cnblogs.com/blog/625732/202001/625732-20200109150955897-106647584.png" alt=""></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
</li>
</ul>
</ul>
<h3>&nbsp;注意</h3>
<ul>
<li>arrayFilter 数组中的顶级字段不能重复,如下:出现了两个 idx0,运行报错&nbsp;<span class="cnblogs_code">index 0: 9 - Found multiple array filters with the same top-level field name idx0</span>&nbsp;
<div class="cnblogs_code"><img id="code_img_closed_1e3662f9-3809-423c-a909-62b3aa423b76" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_1e3662f9-3809-423c-a909-62b3aa423b76" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_1e3662f9-3809-423c-a909-62b3aa423b76" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 0, 1)">db.nestedUpdate.updateMany({}, {
    </span><span style="color: rgba(128, 0, 128, 1)">$set</span><span style="color: rgba(0, 0, 0, 1)">: {
      'arr_1.</span>$.c.$': 1<span style="color: rgba(0, 0, 0, 1)">
    }
}, {
    arrayFilters: [
      {
            </span>//<span style="color: rgba(0, 0, 0, 1)"> idx0 满足条件: 需存在 c 字段
            'idx0.c': {
                </span><span style="color: rgba(128, 0, 128, 1)">$exists</span>: <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">
            },            
      },
      {
            'idx0.a': </span>1<span style="color: rgba(0, 0, 0, 1)">,            
      },
      {
            </span>// idx1: 满足 值为 111<span style="color: rgba(0, 0, 0, 1)">
            'idx1': </span>1111<span style="color: rgba(0, 0, 0, 1)">
      }
    ]
});
</span>&gt; index 0: 9 - Found multiple array filters with the same top-<span style="color: rgba(0, 0, 0, 1)">level field name idx0
at line </span>1, column 1</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
</li>
<li>arrayFilter 中可以嵌套条件,如:
<div class="cnblogs_code"><img id="code_img_closed_f026cf24-dae9-4cc0-8fc6-5a6322489a57" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_f026cf24-dae9-4cc0-8fc6-5a6322489a57" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_f026cf24-dae9-4cc0-8fc6-5a6322489a57" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 0, 1)">db.nestedUpdate.updateMany({}, {
    </span><span style="color: rgba(128, 0, 128, 1)">$set</span><span style="color: rgba(0, 0, 0, 1)">: {
      'arr_1.</span>$.c.$': 1<span style="color: rgba(0, 0, 0, 1)">
    }
}, {
    arrayFilters: [
      {
            </span>//<span style="color: rgba(0, 0, 0, 1)"> idx0 满足条件: 需存在 c 字段
            'idx0.c': {
                </span><span style="color: rgba(128, 0, 128, 1)">$exists</span>: <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">
            },
            'idx0.a': </span>1<span style="color: rgba(0, 0, 0, 1)">,
      },
      {
            </span>// idx1: 满足 值为 111<span style="color: rgba(0, 0, 0, 1)">
            'idx1': </span>1111<span style="color: rgba(0, 0, 0, 1)">
      }
    ]
});

</span>//<span style="color: rgba(0, 0, 0, 1)"> 或

db.nestedUpdate.updateMany({}, {
    </span><span style="color: rgba(128, 0, 128, 1)">$set</span><span style="color: rgba(0, 0, 0, 1)">: {
      'arr_1.</span>$.c.$': 1<span style="color: rgba(0, 0, 0, 1)">
    }
}, {
    arrayFilters: [
      {
            </span>//<span style="color: rgba(0, 0, 0, 1)"> idx0 满足条件: 需存在 c 字段
            idx0: {
                c: {
                  </span><span style="color: rgba(128, 0, 128, 1)">$exists</span>: <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">
                },
                a: </span>1<span style="color: rgba(0, 0, 0, 1)">
            }
      },
      {
            </span>// idx1: 满足 值为 111<span style="color: rgba(0, 0, 0, 1)">
            'idx1': </span>1111<span style="color: rgba(0, 0, 0, 1)">
      }
    ]
});</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
</li>
<li>arrayFilter 必须包含所有的索引的条件。否则出现错误&nbsp;<span class="cnblogs_code"> index 0: 2 - No array <span style="color: rgba(0, 0, 255, 1)">filter</span> found <span style="color: rgba(0, 0, 255, 1)">for</span> identifier 'idx2' <span style="color: rgba(0, 0, 255, 1)">in</span> path 'arr_1.$[].arr_1_1.$.arr1_1_1.$'</span>&nbsp;
<div class="cnblogs_code"><img id="code_img_closed_040f3979-f331-45e0-b4ef-e86b66324158" class="code_img_closed" src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt=""><img id="code_img_opened_040f3979-f331-45e0-b4ef-e86b66324158" class="code_img_opened" style="display: none" src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="">
<div id="cnblogs_code_open_040f3979-f331-45e0-b4ef-e86b66324158" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 0, 1)">db.nestedUpdate1.updateMany({}, {
    </span><span style="color: rgba(128, 0, 128, 1)">$set</span><span style="color: rgba(0, 0, 0, 1)">: {
      'arr_1.</span>$[].arr_1_1.$.arr1_1_1.$<span style="color: rgba(0, 0, 0, 1)">': null
    }
}, {
    arrayFilters: [
      {
            </span>// idx1: 满足 name &lt;= 1<span style="color: rgba(0, 0, 0, 1)">
            'idx1.name': {
                </span><span style="color: rgba(128, 0, 128, 1)">$lte</span>: 1<span style="color: rgba(0, 0, 0, 1)">
            }
      },
      
    ]
})
</span>&gt; index 0: 2 - No array <span style="color: rgba(0, 0, 255, 1)">filter</span> found <span style="color: rgba(0, 0, 255, 1)">for</span> identifier 'idx2' <span style="color: rgba(0, 0, 255, 1)">in</span> path 'arr_1.$[].arr_1_1.$.arr1_1_1.$<span style="color: rgba(0, 0, 0, 1)">'
at line </span>1, column 1
&gt; 时间: 0.003s</pre>
</div>
<span class="cnblogs_code_collapse">完整代码</span></div>
</li>
<li>$ 中的idx 可以自定义名字,只需要arrayFilter中名字一样就可以,如 $, $</li>
<li>不止updateMany可以用,update、findAndUpdate、findAndModify 等也可以用</li>
<li>可以与$[] 一起使用,需保证数组中的所有元素都满足后面的条件,如:
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">db.nestedUpdate1.updateMany({}, {
    </span><span style="color: rgba(128, 0, 128, 1)">$set</span><span style="color: rgba(0, 0, 0, 1)">: {
      'arr_1.</span>$[].arr_1_1.$.arr1_1_1.$<span style="color: rgba(0, 0, 0, 1)">': null
    }
}, {
    arrayFilters: [
      {
            </span>// idx1: 满足 name &lt;= 1<span style="color: rgba(0, 0, 0, 1)">
            'idx1.name': {
                </span><span style="color: rgba(128, 0, 128, 1)">$lte</span>: 1<span style="color: rgba(0, 0, 0, 1)">
            }
      },
      {
            idx2: </span>1<span style="color: rgba(0, 0, 0, 1)">
      }
    ]
})</span></pre>
</div>
<p>运行示意:<img src="https://img2018.cnblogs.com/blog/625732/202001/625732-20200109153103484-1571286702.png" alt=""></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
</li>
</ul>

</div>
<div id="MySignature" role="contentinfo">
    <p></p>
<div style="font-family: Microsoft YaHei, 微软雅黑, MicrosoftJhengHei, 华文细黑, STHeiti, MingLiu; font-size: 14px; background: hsl(220, 23%, 98%) !important; padding: 17px; border: 1px solid hsl(220, 16%, 94%) !important; color: #414857; text-indent: 0">
<p><span style="font-weight: bold; white-space: nowrap">作  者</span>:<strong><span style="color: red">钟成义</span></strong></p>
<p><span style="font-weight: bold; white-space: nowrap">关于博主</span>:C++, C#, Java, Javascript,
    PHP,html,mysql, nosql都知道一点。个人QQ:252619912</p>
<p id="mylocation">


</p>
<p><span style="font-weight: bold; white-space: nowrap">版权声明</span>:非商业性使用 | 转载 - 署名 | 技术研究,请勿进行非法行为</p>


</div>
<p></p><br><br>
来源:https://www.cnblogs.com/zhongchengyi/p/12162792.html
頁: [1]
查看完整版本: mongodb 更新嵌套数组的值