平安国家 發表於 2024-7-26 10:46:06

Mongodb文档和数组的通配符索引应用小结

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">概述</a></li><li><a href="#_label1">应用</a></li><ul class="second_class_ul"><li><a href="#_lab2_1_0">为文档对象建立通配符索引</a></li><li><a href="#_lab2_1_1">为数组对象添加通配符索引</a></li></ul></ul></div><p>学习mongodb,体会mongodb的每一个使用细节,欢迎阅读威赞的文章。这是威赞发布的第97篇mongodb技术文章,欢迎浏览本专栏威赞发布的其他文章。如果您认为我的文章对您有帮助或者解决您的问题,欢迎在文章下面点个赞,或者关注威赞。谢谢。威赞文章都是结合官方文档,翻译整理而来,并对每个知识点的描述都认真思考和实践,对难以理解的地方,使用简单容易理解的方式进行阐述。</p>
<p class="maodian"><a name="_label0"></a></p><h2>概述</h2>
<p>Mongodb的通配符索引,为灵活可变的Mongodb数据结构提供了高效的查询方法。本文结合Mongodb官方文档,详细介绍在嵌入式文档和数组上,通配符索引的结构。</p>
<p>Mongodb为嵌入式文档和数组字段建立通配符索引时,有特殊的逻辑:</p>
<ul><li>当为文档对象建立通配符索引时,Mongodb会扫描文档对象的每一个字段,将文档的每一个字段都加入到该通配符索引中。如果该字段值也是文档对象,则继续向下扫描,将该文档类型的字段添加到通配符索引。当为数组对象建立通配符索引时, Mongodb会扫描数组中的每一个元素,将每一个元素的内容添加到通配符索引。如果该元素是个数组,则将数组整体放入的通配符索引中。</li><li>当数组元素是对象时,则按照添加对象的方式,将该对象的每一个字段添加到通配符索引。</li><li>对于其他类型的字段,通配符索引保存基本的数据类型值。即非对象,非数组类型值。</li></ul>
<p>通配符索引会持续转换构建索引时遇到的嵌套文档或数组,直到遇到基本数值为止。Mongodb将基本数值和该字段的路径,都放入到通配符索引当中。</p>
<p class="maodian"><a name="_label1"></a></p><h2>应用</h2>
<p class="maodian"><a name="_lab2_1_0"></a></p><h3>为文档对象建立通配符索引</h3>
<p>构建集合users并插入数据</p>
<div class="jb51code"><pre class="brush:sql;">db.users.insertOne({
    account: {
      user_name: "SuperAdmin01",
      contact: {
            email: "xyz@example.com",
            phone: "1234567890"
      },
      access: {
            group: "admin"
      }
    }
})</pre></div>
<p>在account字段添加通配符索引</p>
<div class="jb51code"><pre class="brush:sql;">db.users.createIndex({"account.$**": 1})</pre></div>
<p>Mongodb在构建通配符索引时,会解析account对象的每一个字段 ,将每一个字段的值和路径放到索引中</p>
<ul><li>&quot;account.username&quot;: &quot;SuperAdmin01&quot;</li><li>&quot;account.contact.email&quot;: &quot;xyz@example.com&quot;</li><li>&quot;account.contact.phone&quot;: &quot;1234567890&quot;</li><li>&quot;access.group&quot;: &quot;admin&quot;</li></ul>
<p class="maodian"><a name="_lab2_1_1"></a></p><h3>为数组对象添加通配符索引</h3>
<p>创建fleet集合并添加数据</p>
<div class="jb51code"><pre class="brush:sql;">db.fleet.insertOne({
    ship: {
      coordinates: [
            [ 37.786971, -122.399677 ],
            [ 37.786971, -122.399677 ]
      ],
      type: "Cargo Ship",
      captains: [
            {
                name: "John Doe",
                age: 45,
                crew: [ "first mate", "engineer" ]
            }
      ]
    }
})</pre></div>
<p>为ship字段添加索引</p>
<div class="jb51code"><pre class="brush:sql;">db.fleet.createIndex({"ship.$**": 1})</pre></div>
<p>ship字段包含一个数组类型的字段coordinates, 字符类型的字段type, 数组类型的字段captains. 其中数组字段coordinates的元素也是数据,在构建通配符索引时,直接将coordinates字段的数组放入索引当中。captains是文档类型的数据,Mongodb构建通配符索引时,会进一步解析到基本元素,将基本元素放入索引当中。按照这样的规则 ,索引当中,存在下面的数据</p>
<ul><li>&quot;ship.coordinates&quot;:,</li><li>&quot;ship.coordinates&quot;:,</li><li>&quot;ship.type&quot;:&quot;Cargo Ship&quot;,</li><li>&quot;ship.captains.name&quot;:&quot;John Doe&quot;,</li><li>&quot;ship.captains.age&quot;:45,</li><li>&quot;ship.captains.crew&quot;:&quot;first mate&quot;,</li><li>&quot;ship.captains.crew&quot;:&quot;first engineer&quot;</li></ul>
<p>从上面的例子当中可以看到,在构建索引时,并没有把元素在数组中的位置也添加到索引当中。但mongdb也能够使用通配符索引,支持带有数组元素位置的查询。如</p>
<div class="jb51code"><pre class="brush:sql;">db.fleet.find({"ship.captains.0.age": {$gt: 40}})</pre></div>
<p>查看该查询的执行计划</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202407/2024072610412821.png" /></p>
<p>但通配符索引,不支持下面的查询</p>
<div class="jb51code"><pre class="brush:sql;">db.fleet.find({
    "ship.coordinates.0.1": 37.786971
})</pre></div>
<p>查看执行计划,能够看到使用全表扫描,而不是通配符索引。因为通配符索引将整个数组元素作为整体放倒索引数据中。而用户使用数组当中的一个值来查询时,Mongodb选择了全表扫描。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202407/2024072610412822.png" /></p>
<p>Mongodb在构建通配符索引时,不会限制文档数组类型结构的深度。但查询时,如果路径长度超过8, Mongodb会选择其他更高效的索引或全表扫描的方式。</p>
頁: [1]
查看完整版本: Mongodb文档和数组的通配符索引应用小结