MongoDB数据库的使用
<p>MongoDB是一个基于<strong>分布式</strong> <strong>文件存储</strong>的NoSQL数据库,适合存储JSON风格文件的形式。</p><ul>
<li>
<h3>三元素:数据库、集合和文档。</h3>
<ul>
<li><strong>文档</strong>:对应着关系数据库中的行,就是一个对象,由键值对构成,是json的扩展Bson形式,示例
<div class="cnblogs_code">
<pre>{<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">name</span><span style="color: rgba(128, 0, 0, 1)">'</span>:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">guojing</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">gender</span><span style="color: rgba(128, 0, 0, 1)">'</span>:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">男</span><span style="color: rgba(128, 0, 0, 1)">'</span>}</pre>
</div>
</li>
<li><strong>集合</strong>:类似于关系数据库中的表,储存多个文档,结构不固定,示例
<div class="cnblogs_code">
<pre>{<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">name</span><span style="color: rgba(128, 0, 0, 1)">'</span>:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">guojing</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">gender</span><span style="color: rgba(128, 0, 0, 1)">'</span>:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">男</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">}
{</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">name</span><span style="color: rgba(128, 0, 0, 1)">'</span>:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">huangrong</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">age</span><span style="color: rgba(128, 0, 0, 1)">'</span>:18<span style="color: rgba(0, 0, 0, 1)">}
{</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">book</span><span style="color: rgba(128, 0, 0, 1)">'</span>:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">shuihuzhuan</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">heros</span><span style="color: rgba(128, 0, 0, 1)">'</span>:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">108</span><span style="color: rgba(128, 0, 0, 1)">'</span>}</pre>
</div>
</li>
</ul>
</li>
</ul>
<h2>一、环境安装与运行</h2>
<ul>
<li>
<h3>安装</h3>
<div class="cnblogs_code">
<pre>sudo apt-get install mongodb</pre>
</div>
</li>
</ul>
<p> 配置文件为 /etc/mongodb.conf,默认端口号:27017</p>
<ul>
<li>
<h3>启动服务器</h3>
<div class="cnblogs_code">
<pre>sudo service mongodb start<span style="color: rgba(0, 128, 0, 1)">#相当于执行命令 sudo mongod --config /etc/mongodb.conf</span></pre>
</div>
</li>
<li>
<h3>关闭服务器</h3>
<div class="cnblogs_code">
<pre>sudo service mongodb stop</pre>
</div>
</li>
<li>
<h3>重启服务器</h3>
<div class="cnblogs_code">
<pre>sudo service mongodb restart <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">修改了配置文件/etc/mongodb.conf后,需要重启mongodb服务器让配置生效</span></pre>
</div>
</li>
<li>
<h3>启动客户端</h3>
<div class="cnblogs_code">
<pre>sudo mongo</pre>
</div>
</li>
</ul>
<h2>二、数据库操作</h2>
<ul>
<li>
<h3>查看当前数据库</h3>
<div class="cnblogs_code">
<pre>db</pre>
</div>
</li>
<li>
<h3>查看所有数据库</h3>
<div class="cnblogs_code">
<pre>show dbs</pre>
</div>
</li>
<li>
<h3>切换(或创建)数据库</h3>
<div class="cnblogs_code">
<pre>use 数据库名</pre>
</div>
<p>切换数据库,如果数据库不存在,当插入数据或创建集合时,会自动创建这个数据库</p>
</li>
<li>
<h3>删除数据库</h3>
<div class="cnblogs_code">
<pre>db.dropDatabase()</pre>
</div>
<p>删除当前指向的数据库,如果不存在,则什么也不做</p>
</li>
</ul>
<h2>三、集合操作</h2>
<ul>
<li>
<h3>创建</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">db.createCollection(name[,options])
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">name集合名称</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)">options可选,是一个用于指定集合配置的文档,其中capped参数默认不设置上限(false),若设置上限(true)则需要指定参数size,单位字节</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">不设置集合大小</span>
db.createCollection(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">stu</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">设置集合大小</span>
db.createCollection(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">sub</span><span style="color: rgba(128, 0, 0, 1)">"</span>, { capped : true, size : 10 } )</pre>
</div>
</li>
<li>
<h3>查看当前数据库集合</h3>
<div class="cnblogs_code">
<pre>show collections</pre>
</div>
</li>
<li>
<h3>删除集合</h3>
<div class="cnblogs_code">
<pre>db.集合名.drop()</pre>
</div>
</li>
</ul>
<h2>四、数据操作</h2>
<ul>
<li>
<h3>插入</h3>
<div class="cnblogs_code">
<pre>db.集合名.insert(文档) 或 db.集合名.insert([文档...])<br><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">如果不指定_id字段,则分配一个唯一的ObjectId;如果指定_id字段,且_id已经存在时,不做任何操作;如果一次性插入多条数据,以数组的方式传入文档<br></span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 不指定_id</span>
db.stu.insert({name:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">gj</span><span style="color: rgba(128, 0, 0, 1)">'</span>,gender:1<span style="color: rgba(0, 0, 0, 1)">})
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">指定_id</span>
s1={_id:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">20160101</span><span style="color: rgba(128, 0, 0, 1)">'</span>,name:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">hr</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">}
s1.gender</span>=<span style="color: rgba(0, 0, 0, 1)">0
db.stu.insert(s1)</span></pre>
</div>
</li>
<li>
<h3>删除--(注意justOne参数)</h3>
<div class="cnblogs_code">
<pre>db.集合名.remove(条件,{justone:<boolean>}) <span style="color: rgba(0, 128, 0, 1)">#参数</span><span style="color: rgba(0, 128, 0, 1)">justOne默认false,删除多条</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 只删除匹配到的一条数据</span>
<span style="color: rgba(0, 0, 0, 1)">db.stu.remove({gender:0},{justOne:true})
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">删除所有</span>
db.stu.remove({})</pre>
</div>
</li>
<li>
<h3>修改--(注意$set以及multi参数)</h3>
<div class="cnblogs_code">
<pre>db.集合名.update({条件},$操作符,{multi: <boolean>}]) <span style="color: rgba(0, 128, 0, 1)">#参数</span><span style="color: rgba(0, 128, 0, 1)">multi只和$操作符一起使用,默认false,只修改一条数据,true表示修改多条数据</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 不使用操作符$set,修改整条文档</span>
db.stu.update({name:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">hr</span><span style="color: rgba(128, 0, 0, 1)">'</span>},{name:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">mnc</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">})
</span><span style="color: rgba(0, 128, 0, 1)">#使用</span><span style="color: rgba(0, 128, 0, 1)">操作符$set指定属性修改</span>
db.stu.update({name:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">hr</span><span style="color: rgba(128, 0, 0, 1)">'</span>},{$set:{name:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">hys</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">}})
</span><span style="color: rgba(0, 128, 0, 1)">#multi参数和$set一起使用,修改多条文档</span>
db.stu.update({},{$set:{gender:0}},{multi:true})</pre>
</div>
</li>
<li>修改集合字段名
<div class="cnblogs_code">
<pre>db.目标集合.updateMany( {查询条件}, {$rename : { 原名称:新名称 } } )</pre>
</div>
</li>
<li>
<h3>保存</h3>
<div class="cnblogs_code">
<pre>db.集合名.save(document) <br><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">在手动插入_id字段时,如果_id已经存在,做全文档更新操作,其余均表示插入数据。</span></pre>
</div>
<div class="cnblogs_code">
<pre>db.stu.save({_id:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">20160102</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">name</span><span style="color: rgba(128, 0, 0, 1)">'</span>:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">yk</span><span style="color: rgba(128, 0, 0, 1)">'</span>,gender:1<span style="color: rgba(0, 0, 0, 1)">})
db.stu.save({_id:</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">20160102</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">name</span><span style="color: rgba(128, 0, 0, 1)">'</span>:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">wyk</span><span style="color: rgba(128, 0, 0, 1)">'</span>}) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">对上述文档做修改</span></pre>
</div>
</li>
<li>
<h3>查询</h3>
<ul>
<li>
<h4>基本查询</h4>
<div class="cnblogs_code">
<pre>db.集合名.find({条件文档}) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询所有</span>
db.集合名.findOne({条件文档}) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">只查询第一条</span>
db.集合名.find({条件文档}).pretty() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">结果格式化输出</span></pre>
</div>
</li>
<li>
<h4>比较运算符</h4>
<ul>
<li>等于:默认,没有运算符</li>
<li>小于: $lt</li>
<li>小于等于: $lte</li>
<li>大于:$gt</li>
<li>大于等于:$gte</li>
<li>不等于:$ne
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询年龄大于等于18的学生</span>
db.stu.find({<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">age</span><span style="color: rgba(128, 0, 0, 1)">"</span>:{$gte:18}})</pre>
</div>
</li>
</ul>
</li>
<li>
<h4>逻辑运算符</h4>
<ul>
<li>逻辑与:默认</li>
<li>逻辑或:$or
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 查询年龄大于或等于18,并且性别为1的学生</span>
db.stu.find({<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">age</span><span style="color: rgba(128, 0, 0, 1)">"</span>:{$gte:18},<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">gender</span><span style="color: rgba(128, 0, 0, 1)">"</span>:1<span style="color: rgba(0, 0, 0, 1)">})
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询年龄大于18,或性别为0的学生</span>
db.stu.find({$<span style="color: rgba(0, 0, 255, 1)">or</span>:[{<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">age</span><span style="color: rgba(128, 0, 0, 1)">"</span>:{$gt:18}},{<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">gender</span><span style="color: rgba(128, 0, 0, 1)">"</span>:1<span style="color: rgba(0, 0, 0, 1)">}]})
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询年龄小于18或者大于20,性别为1的学生</span>
db.stu.find({$<span style="color: rgba(0, 0, 255, 1)">or</span>:[{<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">age</span><span style="color: rgba(128, 0, 0, 1)">"</span>:{$lt:18}},{<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">age</span><span style="color: rgba(128, 0, 0, 1)">"</span>:{$gt:20}}],<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">gender</span><span style="color: rgba(128, 0, 0, 1)">"</span>:1})</pre>
</div>
</li>
</ul>
</li>
<li>
<h4>范围运算符</h4>
<ul>
<li>在某个范围$in,后面接数组</li>
<li>不在某个范围$nin,后面接数组
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询年龄18、20以及22岁的学生</span>
db.stu.find({<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">age</span><span style="color: rgba(128, 0, 0, 1)">"</span>:{$<span style="color: rgba(0, 0, 255, 1)">in</span>:}})
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询年龄不等于18或20的学生</span>
db.stu.find({<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">age</span><span style="color: rgba(128, 0, 0, 1)">"</span>:{$nin:}})</pre>
</div>
</li>
</ul>
</li>
<li>
<h4>正则表达式</h4>
<ul>
<li>使用/表达式/或者$regex
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询姓黄的学生</span>
db.stu.find({<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">name</span><span style="color: rgba(128, 0, 0, 1)">"</span>:/^黄/<span style="color: rgba(0, 0, 0, 1)">})
db.stu.find({</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">name</span><span style="color: rgba(128, 0, 0, 1)">"</span>:{$regex:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">^黄</span><span style="color: rgba(128, 0, 0, 1)">"</span>}})</pre>
</div>
</li>
</ul>
</li>
<li>
<h4>自定义查询</h4>
<ul>
<li>使用$where:function(){return 满足条件的数据表达式}------运算符使用js语法,比如逻辑与(&&),逻辑或(||)
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询年龄18-22的学生</span>
db.stu.find({$where:function(){<span style="color: rgba(0, 0, 255, 1)">return</span> this.age>18 && this.age<22<span style="color: rgba(0, 0, 0, 1)">}})
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询年龄小于18或者大于22的学生</span>
db.stu.find({$where:function(){<span style="color: rgba(0, 0, 255, 1)">return</span> this.age<18 || this.age>22}})</pre>
</div>
</li>
</ul>
</li>
<li>
<h4>投影</h4>
<ul>
<li>只显示部分字段
<div class="cnblogs_code">
<pre>db.集合名.find({条件},{字段名:1,...}) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">1表示该字段显示,0不显示;_id列默认显示,不显示需要明确设置为0</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询姓名和年龄(显示_id)</span>
db.stu.find({},{name:1,gender:1<span style="color: rgba(0, 0, 0, 1)">})
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询姓名和年龄(不显示_id)</span>
db.stu.find({},{_id:0,name:1,gender:1})</pre>
</div>
</li>
</ul>
</li>
<li>
<h4>skip</h4>
<ul>
<li>跳过指定数量的文档
<div class="cnblogs_code">
<pre>db.集合名.find({条件}).skip(number) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">number默认为0</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询从第3条开始的学生信息</span>
db.stu.find().skip(2)</pre>
</div>
</li>
</ul>
</li>
<li>
<h4>limit</h4>
<ul>
<li>读取指定数量的文档
<div class="cnblogs_code">
<pre>db.集合名.find({条件}).limit(number) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">不写number参数,默认读取所有文档</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">读取3条学生信息</span>
db.stu.find().limit(3)</pre>
</div>
</li>
</ul>
</li>
<li>
<h4>skip和limit合用</h4>
<ul>
<li>不区分先后顺序
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询第5-9条学生信息</span>
db.stu.find().skip(4).limit(5) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">相当于跳过4条数据,选5条</span></pre>
</div>
</li>
</ul>
</li>
<li>
<h4>sort</h4>
<ul>
<li>对结果集进行排序
<div class="cnblogs_code">
<pre>db.集合名称.find({条件}).sort({字段:1,...}) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">1表示升序,-1表示降序</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">根据性别降序,再根据年龄升序</span>
db.stu.find().sort({<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">gender</span><span style="color: rgba(128, 0, 0, 1)">"</span>:-1,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">age</span><span style="color: rgba(128, 0, 0, 1)">"</span>:1})</pre>
</div>
</li>
</ul>
</li>
<li>
<h4>count</h4>
<ul>
<li>对结果集中文档数目进行统计,返回整数
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">db.集合名.find({条件}).count()
或者
db.集合名.count({条件})</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">统计年龄大于20的男生人数</span>
db.stu.count({<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">age</span><span style="color: rgba(128, 0, 0, 1)">"</span>:{$gt:20},<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">gender</span><span style="color: rgba(128, 0, 0, 1)">"</span>:1})</pre>
</div>
</li>
</ul>
</li>
<li>
<h4>distinct</h4>
<ul>
<li>对数据去重,返回的是该字段值去重后组成的列表,比如对‘name’字段去重,则列表中的元素为去重后的name值。
<div class="cnblogs_code">
<pre>db.集合名.distinct(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">字段名</span><span style="color: rgba(128, 0, 0, 1)">"</span>,{条件}) </pre>
</div>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2>五、聚合(aggregate)</h2>
<ul>
<li>
<h3>聚合主要用于计算数据,类似sql中的sum()、avg()</h3>
<div class="cnblogs_code">
<pre>db.集合名.aggregate([{管道:{表达式}}...])</pre>
</div>
</li>
<li>
<h3>管道</h3>
<ul>
<li>
<h4>文档处理完毕后,通过管道进行下一次处理</h4>
</li>
<li>
<h4>常用管道:</h4>
<ul>
<li>$group:将集合中的文档分组,可用于统计结果</li>
<li>$match:过滤数据,只输出符合条件的文档</li>
<li>$project:修改输入文档的结构,如重命名、增加、删除字段、创建计算结果</li>
<li>$sort:将输入文档排序后输出</li>
<li>$limit:限制聚合管道返回的文档数</li>
<li>$skip:跳过指定数量的文档,并返回余下的文档</li>
<li>$unwind:将数组类型的字段进行拆分</li>
</ul>
</li>
</ul>
</li>
<li>
<h3>表达式</h3>
<ul>
<li>
<h4>处理输入文档并输出</h4>
</li>
<li>
<h4>语法:表达式:‘$字段名’</h4>
</li>
<li>
<h4>常用表达式:</h4>
<ul>
<li>$sum:计算总和,$sum:'$字段'表示求和,注意$sum:1表示计数,</li>
<li>$avg:计算平均值</li>
<li>$min:获取最小值</li>
<li>$max:获取最大值</li>
<li>$push:在结果文档中插入值到一个数组中(以列表的方式显示字段值)</li>
<li>$first:根据资源文档的排序获取第一个文档数据</li>
<li>$last:根据资源文档的排序获取最后一个文档数据</li>
</ul>
</li>
</ul>
</li>
<li>
<h3>$group</h3>
<ul>
<li>文档分组,用于统计结果</li>
<li>_id表示分组的依据,使用某个字段的格式为'$字段'
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 统计男、女生人数</span>
db.stu.aggregate([{$group:{<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">_id</span><span style="color: rgba(128, 0, 0, 1)">"</span>:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">gender</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">couter</span><span style="color: rgba(128, 0, 0, 1)">"</span>:{$sum:1<span style="color: rgba(0, 0, 0, 1)">}}}])
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">结果文档中显示_id和counter的值</span></pre>
</div>
</li>
<li>_id按照null分组,会将集合中所有文档分为一组
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 求学生总人数和平均年龄</span>
db.stu.aggregate([{$group:{_id:null,counter:{$sum:1},average_age:{$avg:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">$age</span><span style="color: rgba(128, 0, 0, 1)">"</span>}}}])</pre>
</div>
</li>
<li>使用$$ROOT可以将文档内容加入到结果集的数组中
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">统计男、女生信息</span>
db.stu.aggregate([{$group:{_id:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">$gender</span><span style="color: rgba(128, 0, 0, 1)">"</span>,objects:{$push:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">$$ROOT</span><span style="color: rgba(128, 0, 0, 1)">"</span>}}}])</pre>
</div>
</li>
</ul>
</li>
<li>
<h3>$match</h3>
<ul>
<li>过滤数据,输出符合条件文档
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询年龄大于20的学生</span>
db.stu.aggregate([{$match:{age:{$gt:20<span style="color: rgba(0, 0, 0, 1)">}}}])
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询年龄大于20的男、女生人数</span>
db.stu.aggregate([{$match:{age:{$gt:20}}},{$group:{_id:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">$gender</span><span style="color: rgba(128, 0, 0, 1)">"</span>,counter:{$sum:1}}}])</pre>
</div>
</li>
</ul>
</li>
<li>
<h3>$project</h3>
<ul>
<li>修改输出文档的结构
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查找学生姓名、年龄</span>
db.stu.aggregate([{$project:{<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">_id</span><span style="color: rgba(128, 0, 0, 1)">"</span>:0,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">name</span><span style="color: rgba(128, 0, 0, 1)">"</span>:1,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">age</span><span style="color: rgba(128, 0, 0, 1)">"</span>:1<span style="color: rgba(0, 0, 0, 1)">}}])
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询男生、女生人数,但仅输出人数</span>
db.stu.aggregate([{$group:{_id:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">$gender</span><span style="color: rgba(128, 0, 0, 1)">'</span>,counter:{$sum:1}}},{$project:{_id:0,counter:1}}])</pre>
</div>
</li>
</ul>
</li>
<li>
<h3>$sort</h3>
<ul>
<li>将输入文档排序后输出
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询学生信息,按年龄升序</span>
db.stu.aggregate([{$sort:{age:1<span style="color: rgba(0, 0, 0, 1)">}}])
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询男生、女生人数,按人数降序</span>
db.stu.aggregate([{$group:{_id:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">$gender</span><span style="color: rgba(128, 0, 0, 1)">'</span>,counter:{$sum:1}},{$sort:{counter:-1}}])</pre>
</div>
</li>
</ul>
</li>
<li>
<h3>$limit</h3>
<ul>
<li>限制聚合管道返回的文档数
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询2条学生信息</span>
db.stu.aggregate([{$limit:2}])</pre>
</div>
</li>
</ul>
</li>
<li>
<h3>$skip</h3>
<ul>
<li>跳过指定数量的文档,并返回余下的文档,$skip和$limi合用时,注意先写skip,再写limit
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">查询从第3条开始的学生信息</span>
db.stu.aggregate([{$skip:2<span style="color: rgba(0, 0, 0, 1)">}])
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">统计男生、女生人数,按人数升序,取第二条数据</span>
db.stu.aggregate([{$group:{_id:<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">$gender</span><span style="color: rgba(128, 0, 0, 1)">"</span>,counter:{$sum:1}}},{$sort:{<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">counter</span><span style="color: rgba(128, 0, 0, 1)">"</span>:1}},{$skip:1},{$limit:1}])</pre>
</div>
</li>
</ul>
</li>
<li>
<h3>$unwind</h3>
<ul>
<li>将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值
<div class="cnblogs_code">
<pre>db.集合名称.aggregate([{$unwind:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">$字段名称</span><span style="color: rgba(128, 0, 0, 1)">'</span>}]) </pre>
</div>
</li>
</ul>
</li>
</ul>
<h2>六、索引</h2>
<ul>
<li>
<h3>提升查询速度</h3>
</li>
<li>
<h3>创建大量数据</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">for</span>(var i=0;i<1000000;i++){db.stu.insert({name:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">test</span><span style="color: rgba(128, 0, 0, 1)">'</span>+i,num:i})}</pre>
</div>
</li>
<li>
<h3>性能分析工具:explain("executionStats")</h3>
<div class="cnblogs_code">
<pre>查询语句.explain(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">executionStats</span><span style="color: rgba(128, 0, 0, 1)">"</span>)</pre>
</div>
<p>'millis'后面显示的是查询时间,单位ms</p>
</li>
<li>
<h3>建立索引</h3>
<div class="cnblogs_code">
<pre>db.集合.ensureIndex({属性:1或-1}) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">1表示升序,-1表示降序,建立后的索引名称为"属性_1"或者"属性_-1"</span></pre>
</div>
<p>例如:db.stu.ensureIndex({name:1}),建立后的索引名称为"name_1"</p>
</li>
<li>
<h3>建立唯一索引</h3>
<div class="cnblogs_code">
<pre>db.集合.ensureIndex({属性:1},{<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">unique</span><span style="color: rgba(128, 0, 0, 1)">"</span>:true})</pre>
</div>
</li>
<li>
<h3>建立联合索引</h3>
<div class="cnblogs_code">
<pre>db.集合名.ensureIndex({属性1:1,属性2:1...})</pre>
</div>
</li>
<li>
<h3>查看索引</h3>
<div class="cnblogs_code">
<pre>db.集合名.getIndexes()</pre>
</div>
</li>
<li>
<h3>删除索引</h3>
<div class="cnblogs_code">
<pre>db.集合名.dropIndex(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">索引名称</span><span style="color: rgba(128, 0, 0, 1)">"</span>) </pre>
</div>
</li>
<li>
<h3>创建字段的TTL(Time To Live )索引,设置文档过期时间</h3>
<div class="cnblogs_code">
<pre>db.test.ensureIndex({<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Date1</span><span style="color: rgba(128, 0, 0, 1)">'</span>:1},{expireAfterSeconds:10}) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 索引名:Date1_1</span>
db.test.insertOne({<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Date1</span><span style="color: rgba(128, 0, 0, 1)">'</span>:new Date(),<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Name</span><span style="color: rgba(128, 0, 0, 1)">'</span>:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Lily</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Age</span><span style="color: rgba(128, 0, 0, 1)">'</span>:20})</pre>
</div>
<p>如上设置,所有含有Date1字段的数据,会在入库10秒后过期</p>
</li>
</ul>
<h2>七、数据库安全</h2>
<p style="margin-left: 30px">为了更安全的访问mongodb,需要访问者提供用户名和密码,于是需要在mongodb中创建用户。mongodb数据库采用了角色-用户-数据库的安全管理方式。</p>
<ul>
<li>
<h3>常用系统角色如下:</h3>
<ul>
<li>root:只在admin数据库中可用,超级账号,超级权限</li>
<li>Read:允许用户读取指定数据库</li>
<li>readWrite:允许用户读写指定数据库</li>
</ul>
</li>
<li>
<h3>创建超级管理用户:</h3>
<div class="cnblogs_code">
<pre>use admin <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">首先切换到admin数据库</span>
<span style="color: rgba(0, 0, 0, 1)">
db.createUser({
user:</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">用户名</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">,
pwd:</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">密码</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">,
roles:[{role:</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">root</span><span style="color: rgba(128, 0, 0, 1)">'</span>,db:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">admin</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">}]
})</span></pre>
</div>
</li>
<li>
<h3>启用安全验证</h3>
<ul>
<li>
<h4>修改配置文件( /etc/mongodb.conf)</h4>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">noauth = true</span>
auth = true <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">开启安全验证</span></pre>
</div>
</li>
<li>
<h4>重启服务</h4>
<div class="cnblogs_code">
<pre>sudo service mongodb restart</pre>
</div>
</li>
<li>
<h4>终端连接</h4>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> sudo mongo -u '用户名' -p '密码' --authenticationDatabase '数据库名' </span>
sudo mongo -u <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">admin</span><span style="color: rgba(128, 0, 0, 1)">'</span> -p <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">密码</span><span style="color: rgba(128, 0, 0, 1)">'</span> --authenticationDatabase <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">admin</span><span style="color: rgba(128, 0, 0, 1)">'</span></pre>
</div>
</li>
</ul>
</li>
<li>
<h3>普通用户管理</h3>
<ul>
<li>
<h4>首先使用超级管理员登陆,然后再进行用户管理操作</h4>
</li>
<li>
<h4>创建普通用户</h4>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">db.createUser({
user:</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">用户名</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">,
pwd:</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">密码</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">,
roles:[{role:</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">readWrite</span><span style="color: rgba(128, 0, 0, 1)">'</span>,db:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">数据库名</span><span style="color: rgba(128, 0, 0, 1)">'</span>}...] <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">数组里可以有多个角色文档,比如用户在不同的数据库里都有读写权限</span>
})</pre>
</div>
</li>
<li>
<h3>查看当前数据库的用户</h3>
<div class="cnblogs_code">
<pre>show users</pre>
</div>
</li>
<li>
<h4>修改用户:可以修改pwd、roles属性</h4>
<div class="cnblogs_code">
<pre>db.updateUser(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">用户名</span><span style="color: rgba(128, 0, 0, 1)">'</span>,{pwd:<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">新密码</span><span style="color: rgba(128, 0, 0, 1)">'</span>,roles:[{<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">新角色</span><span style="color: rgba(128, 0, 0, 1)">'</span>}...]})</pre>
</div>
</li>
<li>
<h4>删除用户</h4>
<div class="cnblogs_code">
<pre>use admin<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">切换到admin数据库</span>
db.system.users.remove(条件)</pre>
</div>
</li>
<li>
<h4>终端连接</h4>
<div class="cnblogs_code">
<pre> sudo mongo -u <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">用户名</span><span style="color: rgba(128, 0, 0, 1)">'</span> -p <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">密码</span><span style="color: rgba(128, 0, 0, 1)">'</span> --authenticationDatabase <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">数据库名</span><span style="color: rgba(128, 0, 0, 1)">'</span> </pre>
</div>
</li>
</ul>
</li>
</ul>
<h2>八、复制</h2>
<p style="margin-left: 30px">复制提供了数据的冗余备份,并在多个服务器上存储数据的副本,允许从硬件故障和服务中断中恢复数据,能够实现无宕机维护(自动故障转移与自动恢复)。</p>
<p style="margin-left: 30px">复制至少需要2个节点,其中1个为主节点,其它均为从节点。任何节点均可以成为主节点。</p>
<p style="margin-left: 30px">主节点负责所有写入操作,从节点定期轮询主节点获取这些操作并执行这些操作,从而保证从节点的数据与主节点一致。</p>
<ul>
<li>
<h3>设置复制节点</h3>
<ul>
<li>
<h4>创建数据库文件存放目录(自定义)</h4>
<div class="cnblogs_code">
<pre>mkdir ~/Desktop/<span style="color: rgba(0, 0, 0, 1)">t1
mkdir </span>~/Desktop/t2</pre>
</div>
</li>
<li>
<h4>使用如下格式启动mongod,如果在同一台主机上,注意port不能相同,replSet的名称必须是一致的(名称可以自定义)</h4>
<div class="cnblogs_code">
<pre>sudo mongod --bind_ip 192.168.196.128 --port 27017 --dbpath ~/Desktop/t1 --<span style="color: rgba(0, 0, 0, 1)">replSet rs0
sudo mongod </span>--bind_ip 192.168.196.128 --port 27018 --dbpath ~/Desktop/t2 --replSet rs0</pre>
</div>
</li>
<li>
<h4>连接主服务器(自定义一个)</h4>
<div class="cnblogs_code">
<pre>sudo mongo --host 192.168.196.128 --port 27017</pre>
</div>
</li>
<li>
<h4>初始化</h4>
<div class="cnblogs_code">
<pre>rs.initiate()</pre>
</div>
<p>哪个服务器执行初始化,哪个服务器就作为主节点,rs是mongo服务器中专门用于复本集操作的内置对象</p>
</li>
<li>
<h4>查看当前状态</h4>
<div class="cnblogs_code">
<pre>rs.status()</pre>
</div>
</li>
<li>
<h4>添加副本集</h4>
<div class="cnblogs_code">
<pre>rs.add(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">192.168.127.128:27018</span><span style="color: rgba(128, 0, 0, 1)">"</span>)</pre>
</div>
</li>
<li>
<h4>连接从服务器</h4>
<div class="cnblogs_code">
<pre>sudo mongo --host 192.168.196.128 --port 27018</pre>
</div>
</li>
<li>
<h4>从服务器设置</h4>
<div class="cnblogs_code">
<pre>rs.slaveOk()</pre>
</div>
<p>主服务器插入数据,从服务器就可以读取数据了</p>
</li>
<li>
<h4>删除从节点</h4>
<div class="cnblogs_code">
<pre>rs.remove(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">192.168.196.128:27018</span><span style="color: rgba(128, 0, 0, 1)">'</span>) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">需要在主服务器操作</span></pre>
</div>
</li>
<li>
<h4>模拟故障重启</h4>
<ul>
<li>关闭主服务器后再重新启动,会发现原来的从服务器变为了主服务器,新启动的服务器(原来的主服务器)变为了从服务器,但是注意在重启的服务器上重新设置rs.slaveOk()</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2>九、备份与恢复</h2>
<ul>
<li>
<h3>备份</h3>
<ul>
<li>
<h4>语法</h4>
<div class="cnblogs_code">
<pre>sudo mongodump -h 服务器地址 -d 需要备份的数据库 -o 备份数据存放目录</pre>
</div>
<div class="cnblogs_code">
<pre>mkdir ~/Desktop/test1_bak <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">创建存放备份数据的目录</span>
sudo mongodump -h 192.168.196.128:27017 -d test1 -o ~/Desktop/test1_bak</pre>
</div>
</li>
</ul>
</li>
<li>
<h3>恢复</h3>
<ul>
<li>
<h4>语法</h4>
<div class="cnblogs_code">
<pre>sudo mongorestore -h 服务器地址 -d 恢复后数据库名 --dir 备份数据所在位置</pre>
</div>
<div class="cnblogs_code">
<pre>sudo mongorestore -h 192.168.196.128:27017 -d test2 --dir ~/Desktop/test1_bak/test1</pre>
</div>
</li>
</ul>
</li>
</ul>
<h2>十、python交互</h2>
<ul>
<li>
<h3>安装pymongo包</h3>
<div class="cnblogs_code">
<pre>sudo pip3 install pymongo</pre>
</div>
</li>
<li>
<h3>引入包</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span> pymongo</pre>
</div>
</li>
<li>
<h3>建立连接并创建客户端</h3>
<div class="cnblogs_code">
<pre>有安全认证:client=MongoClient(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">mongodb://用户名:密码@host:27017/数据库</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
无安全认证:client</span>=MongoClient(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">mongodb://localhost: 27017</span><span style="color: rgba(128, 0, 0, 1)">"</span>)</pre>
</div>
</li>
<li>
<h3>获得数据库(以test数据库为例)</h3>
<div class="cnblogs_code">
<pre>db =<span style="color: rgba(0, 0, 0, 1)"> client.数据库名
例如:db </span>= client.test</pre>
</div>
</li>
<li>
<h3>获得集合stu</h3>
<div class="cnblogs_code">
<pre>stu = db.stu</pre>
</div>
</li>
<li>
<h3>数据操作</h3>
<ul>
<li>
<h4>查询</h4>
<ul>
<li>find_one 查找单个文档
<div class="cnblogs_code">
<pre>stu1 = stu.find_one({条件}) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">返回一条文档,字典类型</span></pre>
</div>
</li>
<li>find 查找多个文档
<div class="cnblogs_code">
<pre>cursor = stu.find({条件}) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">返回迭代器对象cursor</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)">方式1:用for循环迭代取值</span>
<span style="color: rgba(0, 0, 255, 1)">for</span> s <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> cursor:
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(s) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">字典类型</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">方式2:用next取值</span>
s1 =<span style="color: rgba(0, 0, 0, 1)"> next(cursor)
s2 </span>=<span style="color: rgba(0, 0, 0, 1)"> next(cursor)
...</span></pre>
</div>
</li>
</ul>
</li>
<li>
<h4>插入</h4>
<ul>
<li>insert_one 插入一条文档
<div class="cnblogs_code">
<pre>stu.insert_one(文档)</pre>
</div>
</li>
<li>insert_many 插入多条文档
<div class="cnblogs_code">
<pre>stu.insert_many([文档1,文档2...])</pre>
</div>
</li>
</ul>
</li>
<li>
<h4>更新</h4>
<ul>
<li>replace_one 更新匹配到的第一条整条文档
<div class="cnblogs_code">
<pre>stu.replace_one({条件}, {文档}, upsert=False)</pre>
</div>
<p>upsert=False(默认)时,如果没有匹配到的文档,则不做任何操作;upsert=True时,匹配到则更新,未匹配到则插入(执行Insert_one操作)</p>
</li>
<li>update_one 与$set一起使用,指定属性修改匹配到的第一条文档
<div class="cnblogs_code">
<pre>stu.update_one({条件},{<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">$set</span><span style="color: rgba(128, 0, 0, 1)">'</span>:{文档}},upsert=False)</pre>
</div>
<p>upsert=False(默认)时,如果没有匹配到的文档,则不做任何操作;upsert=True时,匹配到则更新,未匹配到则插入,示例</p>
<div class="cnblogs_code">
<pre>stu.update_one({<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">name</span><span style="color: rgba(128, 0, 0, 1)">'</span>: <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">刘德华</span><span style="color: rgba(128, 0, 0, 1)">'</span>}, {<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">$set</span><span style="color: rgba(128, 0, 0, 1)">'</span>: {<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">gender</span><span style="color: rgba(128, 0, 0, 1)">'</span>: 0}}, upsert=<span style="color: rgba(0, 0, 0, 1)">True)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 如果根据{'name': '刘德华'}未匹配到结果,则会执行:</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)">stu.insert_one({'name': '刘德华', 'gender': 0})</span></pre>
</div>
</li>
<li>update_many 与$set一起使用,指定属性修改多条文档
<div class="cnblogs_code">
<pre>stu.update_many({条件},{<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">$set</span><span style="color: rgba(128, 0, 0, 1)">'</span>:{文档}}, upsert=False)</pre>
</div>
<p>用法参考upsert_one</p>
</li>
</ul>
</li>
<li>
<h4>删除</h4>
<ul>
<li>delete_one 删除单条文档
<div class="cnblogs_code">
<pre>stu.delete_one({条件})</pre>
</div>
</li>
<li>delete_many 删除多条文档
<div class="cnblogs_code">
<pre>stu.delete_many({条件})</pre>
</div>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2>十一、解决游标连接超时问题</h2>
<ul>
<li>
<h3>原因</h3>
</li>
</ul>
<p style="margin-left: 60px">游标连接单次最大超时时间为10分钟,单次从mongo服务端获取的数据为101条或者1~16M,如果在10分钟内,未处理完获取的所有数据,则会报异常</p>
<ul>
<li>
<h3>解决方案</h3>
</li>
</ul>
<p style="margin-left: 60px">1、设置 no_cursor_timeout=True,即游标连接永不超时,需要手动关闭游标(可以利用with上下文管理器)</p>
<p style="margin-left: 60px">2、减少单次获取的数据量,比如 batch_size=10,即单次获取10条数据</p>
<ul>
<li>
<h3>示例</h3>
<div class="cnblogs_code">
<pre>with 集合.find({},{<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">_id</span><span style="color: rgba(128, 0, 0, 1)">'</span>:0},sort=[('time',1)],no_cursor_timeout=True,batch_size=10<span style="color: rgba(0, 0, 0, 1)">) as cursor:
</span><span style="color: rgba(0, 0, 255, 1)">for</span> result <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> cursor:
parse(result)</span></pre>
</div>
<p>不显示_id字段,按照time字段升序排序,同时单次获取10条数据</p>
</li>
</ul>
<h2> 十二、连接池</h2>
<ul>
<li>
<h3>示例</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">from</span> pymongo <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> MongoClient
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> threading
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> time
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 全局客户端(线程安全)</span>
client =<span style="color: rgba(0, 0, 0, 1)"> MongoClient(
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">mongodb://localhost:27017/</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
maxPoolSize</span>=20<span style="color: rgba(0, 0, 0, 1)">,
waitQueueTimeoutMS</span>=3000<span style="color: rgba(0, 0, 0, 1)">
)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> insert_data(thread_id):
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">:
db </span>=<span style="color: rgba(0, 0, 0, 1)"> client.test_db
db.test.insert_one({</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">thread</span><span style="color: rgba(128, 0, 0, 1)">"</span>: thread_id, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">time</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: time.time()})
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(f<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Thread {thread_id} inserted data</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">except</span><span style="color: rgba(0, 0, 0, 1)"> Exception as e:
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(f<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Thread {thread_id} failed: {e}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 启动10个线程</span>
threads =<span style="color: rgba(0, 0, 0, 1)"> []
</span><span style="color: rgba(0, 0, 255, 1)">for</span> i <span style="color: rgba(0, 0, 255, 1)">in</span> range(10<span style="color: rgba(0, 0, 0, 1)">):
t </span>= threading.Thread(target=insert_data, args=<span style="color: rgba(0, 0, 0, 1)">(i,))
threads.append(t)
t.start()
</span><span style="color: rgba(0, 0, 255, 1)">for</span> t <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> threads:
t.join()
client.close()</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 应用退出时关闭</span></pre>
</div>
<p>单个 <code data-sourcepos="7:15-7:28">MongoClient</code> 实例可被多线程共享。<br>连接在执行完操作后会自动返回到连接池。--- 无需手动归还连接<br>池中有空闲连接,立即复用,无空闲但未达 <code data-sourcepos="92:14-92:27">maxPoolSize</code>,创建新连接。<br>所有连接都在使用中,新请求会等待(最多 <code data-sourcepos="98:27-98:47">waitQueueTimeoutMS</code> 毫秒)</p>
</li>
</ul>
<p>十三、事务(MongoDB 4.0后增加的)</p>
<ul>
<li>手动开启<br>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">with client.start_session() as session:
session.start_transaction()</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 开始事务</span>
<span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 事务操作(例如多个读写)</span>
collection1.update_one({...}, {...}, session=<span style="color: rgba(0, 0, 0, 1)">session)
collection2.insert_one({...}, session</span>=<span style="color: rgba(0, 0, 0, 1)">session)
session.commit_transaction()</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 提交事务</span>
<span style="color: rgba(0, 0, 255, 1)">except</span><span style="color: rgba(0, 0, 0, 1)"> Exception as e:
session.abort_transaction() </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 回滚事务</span>
<span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">事务失败:</span><span style="color: rgba(128, 0, 0, 1)">"</span>, str(e))</pre>
</div>
</li>
<li>自动提交
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">with session.start_transaction():
collection.update_one({...}, {...}, session</span>=<span style="color: rgba(0, 0, 0, 1)">session)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 无需手动 commit/abort</span></pre>
</div>
<ul data-sourcepos="38:1-39:77">
<li data-sourcepos="38:1-38:54"><span data-sourcepos="38:3-38:31">事务必须在同一个会话(<code data-sourcepos="38:16-38:25">session</code>)中执行,且所有操作需传递 <code data-sourcepos="38:41-38:50">session</code> 参数。</span></li>
<li data-sourcepos="38:1-38:54"><span data-sourcepos="38:3-38:31"><span data-sourcepos="39:3-39:16">连接池默认支持事务,无需特殊配置,但需确保 MongoDB 是复制集(Replica Set)或分片集群(Sharded Cluster)---------需要特殊配置,否则会直接报错</span></span></li>
</ul>
</li>
</ul><br><br>
来源:https://www.cnblogs.com/eliwang/p/14587595.html
頁:
[1]