<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://jason-space.netlify.app/feed.xml" rel="self" type="application/atom+xml" /><link href="https://jason-space.netlify.app/" rel="alternate" type="text/html" /><updated>2025-12-04T18:34:53+08:00</updated><id>https://jason-space.netlify.app/feed.xml</id><title type="html">single title</title><subtitle>personal description</subtitle><author><name>Jiaxian Li</name></author><entry><title type="html">MongoDB服务器基础篇</title><link href="https://jason-space.netlify.app/mongodb/" rel="alternate" type="text/html" title="MongoDB服务器基础篇" /><published>2025-11-19T00:00:00+08:00</published><updated>2025-11-19T00:00:00+08:00</updated><id>https://jason-space.netlify.app/MongoDB</id><content type="html" xml:base="https://jason-space.netlify.app/mongodb/"><![CDATA[<blockquote>
  <p>MongoDB服务器基础篇</p>
</blockquote>

<h2 id="前言">==前言==</h2>

<p>注意服务器是一个网站，而客户端通过网站的接口（这里通常27017）连接服务器。</p>

<blockquote>
  <p>数据结构：数据库（database）——集合（collection）——文档（document）——字段</p>
</blockquote>

<p>数据库：网站中的大文件夹。默认有三个：admin、local、config</p>

<p>集合：小文件夹，mysql是表</p>

<p>文档：存取数据的基本单元（Bson格式），mysql是记录。另外还有一种FridFS文件系统可以提供更大的文件系统</p>

<p>字段：则是文档内的数据的分段，每个字段都有无数字典。</p>

<p><img src="/MongoDB.assets/image-20210112133531251.png" alt="image-20210112133531251" style="zoom:80%;" /></p>

<p>数据类型：</p>

<p><img src="/MongoDB.assets/image-20210112133735707.png" alt="image-20210112133735707" style="zoom:80%;" /></p>

<p>参考文档：https://www.runoob.com/mongodb/mongodb-databases-documents-collections.html</p>

<p>环境：</p>

<p>先下载Mongodb环境，</p>

<h2 id="1-部署服务器和连接服务器测试">1. 部署服务器和连接服务器测试</h2>

<h3 id="windows">Windows：</h3>

<h4 id="1----启动部署服务器">1)    启动，部署服务器</h4>

<p>先创建一个文件夹放服务器的数据库，这里在bin同级目录下创建data，里面再创建db，以下为两种方法</p>

<h5 id="方法1命令行启动">方法1：命令行启动：</h5>

<p>直接在bin目录下用<code class="language-plaintext highlighter-rouge">mongod --dbpath=..\data\db</code>（在目录db下创建服务器，并立即启动）</p>

<p>==【注】==</p>

<ol>
  <li>
    <p>mongodb默认数据库的存放位置其实就是\data\db</p>
  </li>
  <li>
    <p>启动信息中可以看到，直接启动mongoDB的默认地址是127.0.0.1（本地服务器），默认端口是27017，如果我们想改变默认的启动端口，可以通过命令行后面–port来指定端口。</p>
  </li>
  <li>
    <p>为了方便我们每次启动，可以将安装目录的bin目录设置到环境变量的path中， bin 目录下是一些常用命令，比如 mongod 启动服务用的， mongo 客户端连接服务用的。</p>
  </li>
</ol>

<h5 id="方法2配置文件启动">方法2：配置文件启动：</h5>

<p>也可用config的配置文件来启动，在bin同级目录下创建config文件夹，再创建mongod.conf文档</p>

<p>输入命令<code class="language-plaintext highlighter-rouge">mongod -f ..\config\mongod.conf </code>或 <code class="language-plaintext highlighter-rouge">mongod --config ..\config\mongod.conf</code></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>storage:
  #The directory where the mongod instance stores its data.Default Value is "\data\db" on Windows
  #注意这里通过这个配置文件启动早已创建好的服务器（方法1创建的），这条路径是刚刚创建创建服务器的位置
  dbPath:E:\test_code\mongodb-win32-x86_64-2008plus-ssl-4.0.12\data\db
  #注意前面是空格，配置文件不可有tab
  #路径：若路径中有空格，则需要加双引号；一般填路径无需双引号，如果加上双引号，把盘符\改成/或//；
</code></pre></div></div>

<p>另外配置文件可再详细（设置了多设置了日志存储文件，并设置改端口IP，可改成服务器的局域网IP）</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemLog:
  destination: file
  #The path of the log file to which mongod or mongos should send all diagnostic logging information
  path: "E:/test/mongodb/mongodb/data/log/mongodb.log"
  logAppend: true
storage:
  journal:
    enabled: true
    #The directory where the mongod instance stores its data.Default Value is "/data/db".
  dbPath: "E:/test/mongodb/mongodb/data/db"
net:
  #bindIp: 127.0.0.1
  port: 27017
setParameter:
  enableLocalhostAuthBypass: false
</code></pre></div></div>

<p>==【注】配置文件不可有tab制表符，只可用空格，空格不可过多，==</p>

<h4 id="2----客户端连接服务器">2)    客户端连接服务器：</h4>

<p>这里是测试刚才创建的服务器，不可把服务器的CMD窗口关闭</p>

<p>服务器里一般默认有三个数据库）</p>

<h5 id="方法1命令行monogo适合本地连接">方法1.命令行monogo（适合本地连接）</h5>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#无任何参数，一般访问本地
mongo 		
#或带参数，指定本地地址及端口
mongo --host=127.0.0.1 --port=27017
</code></pre></div></div>

<p>其他一些命令行操作（MongoDB javascript shell是一个基于javascript的解释器，故是支持js程序的。）</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>show dbs		//显示数据库，也可写databases
exit			//离开mongodb
mongo --help	//更多参数
</code></pre></div></div>

<h5 id="方法2利用图形化界面mongodb-compass连接服务器">方法2：利用图形化界面mongodb Compass连接服务器</h5>

<p>直接打开输入地址和端口即可，若本地服务器直接填localhost或者127.0.0.1</p>

<p><img src="/MongoDB.assets/compass_interface.png" alt="compass_interface" style="zoom:67%;" /></p>

<h3 id="linux">Linux:</h3>

<p>这里介绍真正用虚拟机或服务器搭建非本地的服务器</p>

<h4 id="1预操作">1.预操作</h4>

<p>（1） 官网下载mongodb的linux压缩包 mongod-linux-x86_64-4.0.10.tgz 。 压缩包可直接使用，免安装，省心</p>

<p>（2）上传压缩包到Linux中，解压到当前目录：  <code class="language-plaintext highlighter-rouge">tar -xvf mongodb-linux-x86_64-4.0.10.tgz</code></p>

<p>（3）为了方便管理mongodb文件，移动解压后的文件夹到指定的目录中： <code class="language-plaintext highlighter-rouge">mv mongodb-linux-x86_64-4.0.10 /usr/local/mongodb</code></p>

<p>（4）==新建几个目录，分别用来存储数据和日志==：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir -p /mongodb/single/data/db 								#数据存储目录
mkdir -p /mongodb/single/log vi /mongodb/single/mongod.conf		#日志存储目录
</code></pre></div></div>

<p>（5）新建并修改配置文件 配置文件的内容如下：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#设置MongoDB发送所有日志输出的目标指定为文件
systemLog:
  #指定对日志的操作是文件操作，默认是命令行操作。这是方便代码维护
  destination: file
  #mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  path: "/mongodb/single/log/mongod.log"
  #当mongos或mongod实例重新启动时，mongos或mongod会将新条目附加到现有日志文件的末尾。
  logAppend: true
storage:
  #mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。默认数据存放位置是"/data/db"
  dbPath: "/mongodb/single/data/db"
  journal:
  #启用或禁用持久性日志以确保数据文件保持有效和可恢复。
  enabled: true
processManagement:
  #启用在后台运行mongos或mongod进程的守护进程模式，即保证后台一直运行。
  fork: true
net:
  #服务实例绑定的IP，默认是localhost，这里是设置服务器局域网的IP
  bindIp: localhost,192.168.0.2
  #bindIp
  #绑定的端口，默认是27017
  port: 27017
</code></pre></div></div>

<p>（6）启动MongoDB服务：<code class="language-plaintext highlighter-rouge">/usr/local/mongodb/bin/mongod -f /mongodb/single/mongod.conf</code></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[root@bobohost single]# /usr/local/mongodb/bin/mongod -f /mongodb/single/mongod.conf	#启动进程
about to fork child process, waiting until server is ready for connections.
forked process: 90384
child process started successfully, parent exiting
</code></pre></div></div>

<p>注意：
若无 successfully 提示则表示失败。一般是配置文件有问题。
可以通过通过进程来查看服务是否启动了：<code class="language-plaintext highlighter-rouge">ps -ef |grep mongod</code></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[root@bobohost single]# ps -ef |grep mongod		#查询进程
root 90384 1 0 8月26 ? 00:02:13 /usr/local/mongdb/bin/mongod -f /mongodb/single/mongod.conf
</code></pre></div></div>

<p>（7）分别使用mongo命令和compass工具来连接测试。
==提示==：如果远程连接不上，需要配置防火墙放行，或直接关闭linux防火墙</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#查看防火墙状态
systemctl status firewalld
#临时关闭防火墙
systemctl stop firewalld
#开机禁止启动防火墙
systemctl disable firewalld
</code></pre></div></div>

<p>（8）停止关闭服务(linux关闭服务器比较麻烦)
停止服务的方式有两种：快速关闭和标准关闭，下面依次说明：
（一）快速关闭方法（快速，简单，数据可能会出错）
目标：通过系统的kill命令直接杀死进程：
杀完要检查一下，避免有的没有杀掉。
==【补充】==
如果一旦是因为数据损坏，则需要进行如下操作：
1）删除lock文件：
2）修复数据：</p>

<p>（二）标准的关闭方法（数据不容易出错，但麻烦）：
目标：通过mongo客户端中的shutdownServer命令来关闭服务
主要的操作步骤参考如下：
3 基本常用命令
#bindIp
#绑定的端口，默认是27017
port: 27017</p>

<h4 id="2启动一般用配置文件配置详细">2.启动：一般用配置文件配置（详细）</h4>

<ol>
  <li>
    <p>首先创建数据存储目录和日志存储目录（均是数据库，即文件）</p>
  </li>
  <li>
    <p>创建配置文件，指定上面两个目录，并自动后台执行，确定服务器地址和端口（一般是云服务器所在的局域网地址，非公网）</p>
  </li>
</ol>

<h4 id="3连接同上注意连公网不同于配置服务器地址">3.连接：同上,注意连公网(不同于配置服务器地址)</h4>

<h1 id="2---数据库数据处理">2   数据库数据处理</h1>

<p><img src="/MongoDB.assets/sql.png" alt="sql" style="zoom:67%;" /></p>

<p>可以理解为文件夹是数据库；</p>

<p>数据库内有文件（数据库表）；</p>

<p>每个文档内有多条数据，一条数据即数据记录行，也就是是超多的键：值</p>

<p>其中有主键_id</p>

<p>对比关系数据库RDBMS</p>

<p><img src="MongoDB.assets/image-20210111095542025.png" alt="image-20210111095542025" /></p>

<p>一般内置三个服务器：</p>

<p>Admin：类似root库，存储用户信息及相应权限</p>

<p>Local：集群算数处理时保证绝对不会复制</p>

<p>Config：用于创建集群的分片</p>

<h2 id="21-数据库">2.1 数据库</h2>

<h3 id="基础操作">基础操作</h3>

<p><strong>创建/切换数据库（文件夹）：</strong></p>

<p>格式：use 数据库名</p>

<p>【注】只有数据库有内容时（集合），才存储到硬盘，否则只是在内存中</p>

<p><strong>查询当前数据库：</strong></p>

<p>格式：<code class="language-plaintext highlighter-rouge">db</code></p>

<p><strong>删除数据库：</strong></p>

<p>格式：<code class="language-plaintext highlighter-rouge">db.dropdatabase（）</code></p>

<p>类似js的语法，保证当前使用的是想要删除的数据库，在输入命令</p>

<h3 id="数据库管理">数据库管理</h3>

<h5 id="数据库的备份和恢复">数据库的备份和恢复</h5>

<blockquote>
  <p>要注意这里的命令是在系统命令行输入的，其他操作都是在mongodb服务器的操作</p>
</blockquote>

<p>恢复的数据是以前删除的json和bson的数据</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>//数据备份
mongodump -h dbhost -d dbname -o dbdirectory
//-h:MongDB所在服务器地址，例如:127.0.0.1，当然也可以指定端口号:127.0.0.1:27017。默认是本地端，即127.0.0.1
//-d:需要备份的数据库名，例如：test
//-o:备份的数据存放位置，例如：c:\data\dump，当然该目录需要提前建立，在备份完成后，系统自动在dump目录下建立一个test目录，这个目录里面存放该数据库实例的备份数据。

//数据恢复
mongorestore -h &lt;hostname&gt;&lt;:port&gt; -d 数据库名 &lt;path&gt;

//--host &lt;:port&gt; 或 -h &lt;:port&gt; : MongoDB所在服务器地址，默认为: localhost:27017
//--db,-d :需要恢复的数据库名，例如：test，当然这个名称也可以和备份时候的不一样，比如test2
//--drop :恢复的时候，先删除当前数据，然后恢复备份的数据。就是说，恢复后，备份后添加修改的数据都会被删除，慎用哦！

//&lt;path&gt; :mongorestore 最后的一个参数，设置备份数据所在位置，例如：c:\data\dump\test。
//--dir :指定备份的目录
	//不可同时指定 &lt;path&gt; 和 --dir 选项


</code></pre></div></div>

<h5 id="数据库的复制">数据库的复制</h5>

<p>为了防止数据库的死机导致数据完全丢失，所以会创建很多副本集，一个死了用其他副本集</p>

<p>整体结构是有一个数据库做主节点，其余是从节点。主节点负责直接和客户端收发数据，并产生操作的日志oplog，从节点读取主节点的oplog然后做同样的操作，从而保证数据库的自动备份</p>

<h5 id="数据库的分片">数据库的分片</h5>

<p>对于超大型的服务器，要处理海量的数据，一台机器可能不足以存储数据，并且吞吐量也不满足要求，所以会将数据分割给多台机器</p>

<p>分片的启动的客户端称shard serve</p>

<h5 id="数据库的监控">数据库的监控</h5>

<p>mongostat和mongotop是和mongod和mongo一样在bin目录下，只需到该目录启动即可</p>

<ul>
  <li>
    <p>mongostat实时监控mongodb的运行状况，一般在数据库变慢时使用</p>
  </li>
  <li>
    <p>mongotop可以跟踪mongodb数据库的情况。检测在不同数据上花费的时间</p>

    <p>格式：<code class="language-plaintext highlighter-rouge">mongotop &lt;sleeptime&gt;</code> ,sleeptime是等待的时间</p>
  </li>
</ul>

<p><img src="/MongoDB.assets/image-20210113143810739.png" alt="image-20210113143810739" style="zoom:80%;" /></p>

<h2 id="22-集合">2.2 集合</h2>

<ol>
  <li>
    <p>集合实际是文档，文档中有一条条数据每条数据可以有个键和值，基本操作是==增删改减==。</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#以下为一个集合，一个数据一个{}，其中有多个内容
{"_id":"1","userid":"1002","nickname":"相忘于江湖","createdatetime":new Date("2019-08-
05T22:08:15.522Z"),"likenum":NumberInt(1000)},
{"_id":"2"，"userid":"1005","nickname":"伊人憔悴","createdatetime":new Date("2019-08-05T23:58:51.485Z"),"likenum":NumberInt(888)},
{"_id":"3","userid":"1004","nickname":"杰克船长","createdatetime":new Date("2019-08-06T01:05:06.321Z"),"likenum":NumberInt(666),"state":"1"},
</code></pre></div>    </div>
  </li>
  <li>
    <p>文档格式是bson，其实是类似于json的数据格式。{数据名：数据；}即=={键：值}==</p>

    <p>==一般数字是double类型，其他一般是字符类型==</p>
  </li>
  <li>
    <p>对于每一条数据通常都有自己的主键：==_id==，这是默认的，属性是objectID，内容包括时间戳，机器ID，mongdb服务进程id，最后三个字节为简单的增量值。</p>

    <p>也可自定义_id</p>
  </li>
  <li>
    <p>内置方法</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>NumberInt(数字)	double准换为整型数
new_Data（）		#当前日期
   
#检查数据问题,一般插入数据有问题mongodb不会反馈，若有问题打印相应问题
try
{
db.集合名.inserMany([{},{}]);
}
catch(e){print(e);}
</code></pre></div>    </div>
  </li>
</ol>

<h4 id="集合操作">集合操作</h4>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>//创建集合
db.createCollection(“集合名“,^参数操作^)
//参数可加可不加

//显示当前库的集合
show collections或show tables

//删除集合：返回true或false
db.集合名.drop（）
</code></pre></div></div>

<p>【注】</p>

<ol>
  <li>集合名不可有$或system开头的名称（系统内置集合）</li>
  <li>==当插入数据时，指定的集合不存在，会自动创建新的集合。所以其实集合操作用的少==</li>
</ol>

<p><img src="/MongoDB.assets/image-20210111135818521.png" alt="image-20210111135818521" style="zoom:67%;" /></p>

<h4 id="集合中插入数据"><strong>集合中插入数据：</strong></h4>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>//普通插入
db.集合名.insert({键:值，order：true/false})
//这里键一般是字符，值可以是字符或数字。
//order，true则集合有序，false无序。默认是有序

//插入一条数据
db.集合名.insertOne({键：值,...}，^{writeConcern:参数}^)
//writeConcern写入策略，默认1:要求写操作;0是不要求

//插入多条数据
db.集合名.insertMary({数据名：内容…}，{数据名：内容}...
					^{writeConcern:参数，ordered:参数}^)
//writeConcern写入策略，默认1:要求写操作;0是不要求
//order指定是否顺序写入，默认true是
</code></pre></div></div>

<p>【注】若插入的数据中_id的值与数据库内部重复，将报错；_</p>

<p>​	另外有一种save（）是可以相同的_id,此时会更新</p>

<h4 id="查询集合"><strong>查询集合</strong></h4>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>//查询集合所有数据
db.集合名.find(^{条件query}^,^{条件2projection}^)
//无参数即查询所有数据
//query:查询符合条件的数据
//projection:当条件有两个参数时，即投影查询，查找符合条件的数据，并只显示查找的数据信息，一般来说这样的数据只有_id不同
//条件:数字一般用:表等于，其他正则表达有大于等于等
	   字符串表等于:/字符串/。而其他用$符表示的是正则表达式。
	   数组用find(键:{$in["内容","内容"...]})


//正则
db.集合名.find({键:{$gt:值1,值2}})


//查询第一个符合条件的数据
db.集合名.findOne(^参数query^,^参数projection^)


//多个条件的查询。AND和OR，以普通查询为例
//AND，逗号即相当于AND，查找同时符合两个条件的数据
db.集合名.find( { $and:[{条件1},{条件2}] } )	或	db.集合名.find({条件1，条件2})

//OR,$or,查询符合两个条件中任意一个的数据
db.集合名.find( {$or: [{键1:值1,键2:值2},{键3:值3,键4:值4}] } )


//方法
.pretty()		   //将数据更好看的格式显示
.limit（数字n）		//只对前n条数据条件查询，后面不查
.skip（数字n）		//跳过前n条数据开始条件查询
以上两个也可拼接.skip（n）.limit（m）：跳过前n个只查m个

.sort(键：参数)		//以某个键的值按顺序排序
				   //参数:1是升序，-1是降序
.explain(参数)	 //用来测试查询的性能，一般是测试索引的效果。称为执行计划
				  //返回值有各种PLAN，重要的事winnerPlan，其中有stage返回一个扫描的操作，COLLSCAN代表集合扫描，即全局扫描。若是fetch则是利用索引抓取


</code></pre></div></div>

<h5 id="正则代码">正则代码：</h5>

<p><img src="/MongoDB.assets/image-20210111155903381.png" alt="image-20210111155903381" style="zoom: 80%;" /></p>

<h5 id="type操作符">type操作符</h5>

<p>假设一个不同数据中含有相同的键，但不用数据键的内容格式不同。假设有一个键叫key，可能第一条数据value是字符串，另一条是数据。可以只取某种数据类型的数据</p>

<p>例：<code class="language-plaintext highlighter-rouge">db.col.find({"title":{$type:2}})</code>或<code class="language-plaintext highlighter-rouge">db.col.find({"title":{$type:'string'}})</code></p>

<p><img src="/MongoDB.assets/image-20210111164346258.png" alt="image-20210111164346258" style="zoom:80%;" /></p>

<h4 id="修改集合"><strong>修改集合</strong></h4>

<p>格式：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>//先查找符合条件的数据，后修改此数据的相应内容

db.集合名.update（{条件}，{^$操作符:^{修改内容}}，^upsert:参数^,^multi：参数^,^writeConcern：参数^）

//修改内容可以加上各种更新操作符。$set,$inc
//$set表示只修改数据中的某条数据，若无此语句，则是把该数据的所有内容擦除，再插入给定的内容
//$inc是自增


//upset:当源数据库无符合要求的数据是否插入:默认false，不插入，true为可插入
//multi:查询数量。默认false，只更新一条默认。true符合条件均修改。注意multi与$同时存在才有效
//writeConcern:抛出异常级别

</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">db.集合名.update（{条件}，{新的内容}）</code>    把符合条件数据第一条的内容完全擦除再写入新的</p>

<p><code class="language-plaintext highlighter-rouge">db.集合名.update（{条件}，{$set：{数据名：内容}} </code>  查找符合条件的第一个数据并修改</p>

<p><code class="language-plaintext highlighter-rouge">db.集合名.update（{条件}，{$set：{数据名：内容}，multi:true} </code>  符合条件的所有数据均修改</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>//实例，只添加第一条：
db.col.update( { "count" : { $gt : 4 } } , { $set : { "test5" : "OK"} },true,false );
</code></pre></div></div>

<h4 id="删除集合">删除集合</h4>

<p>删除方式：justOne：true和false。默认false，删除多条，改true只删一条</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
db.集合名.remove
(
   {query条件},
   {
     justOne: &lt;boolean&gt;,
     writeConcern: &lt;document&gt;
   }
)

//query:删除的文档的条件，若不写则是删除所有数据
//justOne:（可选）:删除文档的数量，默认false，删除所有符合条件的数据。 true ，则只删除一个文档
//writeConcern:（可选）抛出异常的级别


//新版
db.集合名.deleteOne({条件})//删除一个
db.集合名.deleteMany({条件})//删除多个

//要注意以上删除不释放磁盘空间
db.repairDatabase()
</code></pre></div></div>

<p>db.集合名.reout(““条件””：)</p>

<h4 id="查重">==查重==</h4>

<blockquote>
  <p>查重其实是非常重要的操作，不光是用户输入的相同信息的过滤，包括可以防止爬虫时重复爬取网站等情况</p>
</blockquote>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>//查找数据中的某个键所有值的种类(以数组的方式呈现)
db.集合名.distinct({键}，^{筛选条件}^)
</code></pre></div></div>

<p>这里介绍一些去重的算法（针对爬虫）：</p>

<p>利用数据库建立索引进行，针对爬取的信息用网站分类或用数据本身进行分类</p>

<ul>
  <li>
    <p>根据url地址进行去重</p>

    <ul>
      <li>
        <p>使用场景：</p>

        <ul>
          <li>url地址对应的数据不会变的情况，url地址能够唯一判别一个条数据的情况（一般url地址的数据不变的）</li>
        </ul>
      </li>
      <li>思路
        <ul>
          <li>所有url数据存在redis中</li>
          <li>拿到url地址，判断url在redis的url的集合中是够存在</li>
          <li>存在：说明url已经被请求过，不再请求</li>
          <li>不存在：url地址没有被请求过，则请求把该url存入redis的集合中</li>
        </ul>
      </li>
      <li>布隆过滤器（一种将多条数据编码的方式方便快速大量查找，例8条数据编码为三位，满足111才便是某条数据存在）
        <ul>
          <li>
            <p>使用多个加密算法加密url地址，得到多个值</p>
          </li>
          <li>
            <p>往对应值的位置把结果设置为1</p>
          </li>
          <li>
            <p>新来一个url地址，一样通过加密算法生成多个值</p>
          </li>
          <li>
            <p>如果对应位置的值全为1，说明这个url地址已经抓过</p>
          </li>
          <li>
            <p>否则没有抓过，就把对应位置的值设置为1</p>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li>
    <p>根据数据本身进行去重（一般数据内可能存在评论增加等数据增加的情况）</p>
    <ul>
      <li>选择特定的字段，使用加密算法(md5,sha1)将字段进行加密，生成字符串，存入redis的集合中</li>
      <li>后续新来一条数据，同样的方法进行加密，如果得到的字符串在redis中存在，说明数据存在，对数据进行更新，否则说明数据不存在，直接插入</li>
    </ul>
  </li>
</ul>

<h4 id="索引">索引</h4>

<p>索引是为了方便数据查询的速度，可以把数据按照一种排列规则添加对应的索引，存放在索引表中</p>

<p>默认有一个索引，就是_id</p>

<p>索引的名称一般是<code class="language-plaintext highlighter-rouge">键_排序参数</code>。符合索引名称则是<code class="language-plaintext highlighter-rouge">键_排序参数_键_排序参数</code></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>//查看索引
db.集合名.getIndexes()
//其中会有v：指Mongodb版本。key：即索引的内容。name：即索引的名称。



//查看索引大小
db.col.totalIndexSize()

//删除索引所有
db.col.dropIndexes()

//删除指定索引，可以是索引名称，也可以是以前输入的索引的内容
db.col.dropIndex("索引名称")

//创建索引
db.collection.createIndex({键:排序参数}, ^{参数:参数}^)
//与find().sort()类似，创建一个以某个键为指标的升序或降序的索引。且这个索引可以多个，但第一条为首要
//排序参数1为升序，-1为降序
//参数见如下，设定索引的类型


</code></pre></div></div>

<p><img src="/MongoDB.assets/image-20210111173720991.png" alt="image-20210111173720991" style="zoom:80%;" /></p>

<h4 id="文档查询">文档查询</h4>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>//统计查询，即查询相应记录的数量
db.集合名.count({条件},参数)
//不带参数则是统计所有

</code></pre></div></div>

<h4 id="聚合">聚合</h4>

<p><strong>聚合</strong>是一种利用管道的方式处理数据并返回结果，一般并不对数据进行改动，只是一定的统计计算。==实际属于查询==</p>

<p>aggergate内的参数是一些筛选条件，<strong>管道</strong>实际上是指把 前一段筛选出的数据提供给下一条筛选，以达到层层筛选的效果</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
//基本处理是将每一个{}的处理结果传给下一个{}

db.集合名.aggergate({管道筛选条件1},{管道筛选条件2}...)

//这里管道筛选条件是group、match等操作，内部可以嵌套一些表达式
//其实处理上来说聚合类似于find，但可以做的操作更多，而且是以管道的方式，所以更有优势



//下表有表达式的图和操作，注意表达式处理的对象一般是key需要$key所有这类key均做此操作
//特别提一下$sum

db.集合名.aggregate([{键:{$sum:1}}])
db.集合名.aggregate([{键:{$sum:$值}}])

//第一个是将统计指定键的数量，有一个这个键就+1
//第一个是将指定键中的值求和

</code></pre></div></div>

<ul>
  <li>表达式</li>
</ul>

<p><img src="/MongoDB.assets/image-20210112085810597.png" alt="image-20210112085810597" style="zoom:80%;" /></p>

<ul>
  <li>管道操作：一般格式：<code class="language-plaintext highlighter-rouge">管道操作符:{操作1，操作2}。内部的操作1,2均是管道处理方式而不是逻辑与的同时处理</code></li>
</ul>

<p><code class="language-plaintext highlighter-rouge">$group</code>：将集合中的文档分组，可用于统计结果。</p>

<p><code class="language-plaintext highlighter-rouge">$match</code>： 用于过滤数据，只输出符合条件的文档。相当于MongoDB的标准查询操作。</p>

<p><code class="language-plaintext highlighter-rouge">$project</code>：修改输入文档的结构。可以用来重命名、增加或删除域，也可以用于创建计算结果以及嵌套文档。</p>

<p><code class="language-plaintext highlighter-rouge">$limit</code>：用来限制MongoDB聚合管道返回的文档数。</p>

<p><code class="language-plaintext highlighter-rouge">$skip</code>：在聚合管道中跳过指定数量的文档，并返回余下的文档。</p>

<p><code class="language-plaintext highlighter-rouge">$unwind</code>：将文档中的某一个数组类型字段拆分成多条,每包含数组中的一一个值。</p>

<p><code class="language-plaintext highlighter-rouge">$sort</code>：将输入文档排序后输出。</p>

<p><code class="language-plaintext highlighter-rouge">$geoNear</code>：输出接近某一地理位置 的有序文档。</p>

<h5 id="group分组">$group分组</h5>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>//$group将文档的分组，用于统计数据。
//$group分组的依据是_id，这是系统内置和group一起工作的，后面的数据则是管道操作
db.集合名.aggregate({ $group: { _id: 键1, 键10:{$sum:1} } });
//这里用了group和sum一起处理数据，表示先将文档以键的值种类分组，再将统计每个组拥有键1的个数

//多条件的group
//假设键中有两种值，分组后的组1有5个拥有键10的数据，组2有6个。处理的结果是{_id:值1,键10:5},{_id:值2,键10=6}
db.集合名.aggregate({ $group: { _id: {键1:"$键1",键1:"$键2"}, 键10:{$sum:1} } });
//_id后面的不仅可以是键值，也可以是一个字典，也就是复合分组。分组的依据有多个。一般用来去重（重复的可以进行sum:1统计处理）。
</code></pre></div></div>

<p>==【注】==</p>

<ul>
  <li>取不同字段的值需要用’’$’‘，例取数据已有的的键</li>
  <li>分组可以按多个键进行分组，嵌套的形式<code class="language-plaintext highlighter-rouge">{$group:{_id:{键1:"$键1",键2:"$键2"} }}</code>
    <ul>
      <li>结果是：<code class="language-plaintext highlighter-rouge">{_id:{键1:"内容1",键2:"内容11"}}，{_id:{键1:"内容2",键2:"内容11"}}</code>类推</li>
    </ul>
  </li>
  <li>以上输出的结果是id底下是一个字典，想要取id下一个字典的键值可以用.取。如：<code class="language-plaintext highlighter-rouge">$_id.键1</code></li>
  <li>==group分组的_id也可填null，这样就可以保证不动不做管道处理，只做表达式操作==</li>
</ul>

<h5 id="match匹配过滤">$match匹配过滤</h5>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>db.集合名.aggregate({$match:{键:{^正则操作符:^值}}});
</code></pre></div></div>

<p>即类似find的普通条件查询</p>

<h5 id="project重命名数据结构">$project重命名数据结构</h5>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>//由于分组的结果一般是_id表示数据，不好看，可以用project重命名组的名字

db.集合名.aggergate([$project:{新键名:"$旧键名1",旧键名2:1,旧键名3:0}])

//对旧键1的操作实际是重命名为新的键名;旧键2的操作是输出结果有键2,注意前提是前面的管道处理的结果有键2;旧键3的操作是不显示旧键3的输出
</code></pre></div></div>

<p>project一般放在最后，重命名</p>

<h5 id="unwind拆分某数组">$unwind拆分某数组</h5>

<p>将文档中的所有的数组类型拆分成多个数据段</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$unwind
将文档中的某一个数组类型字段拆分成多条，每条包含数组中的一个值
语法:db.集合名称.aggregate({$unwind:'$字段名称})


//例：
db.集合名.insert({_id:1,item:'t-shirt,size:['S",'M',L')db.t2.aggregate({$unwind: '$size'})
//结果如下:
{ "_id" : 1, "item" : "t-shirt", "size" : "s"}
{ "_id" : 1, "item" : "t-shirt", "size": "M"}
{ "_id" : 1, "item" : "t-shirt", "size": "L"}

</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>//可选参数：preserveNullAndEmptyArrays。
//默认是false，当有的字段有数组，有的没有，系统会忽视那些没有数据的字段当值为true表示保留属性值为空的文档

db. inventory.aggregate( {
			$unwind : {
				path: '$字段名称'，
				preserveNullAndEmptyArrays :&lt;boolean&gt;		#true或false
				}
})

</code></pre></div></div>

<h5 id="sort输出排序">$sort输出排序</h5>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>db.集合名.aggergate({$sort:{键:1,键2:-1})
//设定以某键升序和降序，和.sort()操作基本一致
</code></pre></div></div>

<h5 id="limit限制返回文档数和skip跳过指定数量的文档"><code class="language-plaintext highlighter-rouge">$limit</code>限制返回文档数和<code class="language-plaintext highlighter-rouge">$skip</code>跳过指定数量的文档</h5>

<p>和find的两个方法基本一致</p>

<h5 id="聚合实例">聚合实例</h5>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/*需求：
统计出每个country和每个province下的userid的数量(同一个userid只统计一次)

处理对象：
{ "country" : "china", "province" : "sh", "userid" : "a"}
{ "country" : "china", "province" : "sh", "userid" : "b"}
{ "country" : "china", "province" : "sh", "userid" : "a"}
{ "country" : "china", "province" : "sh", "userid" : "c"}
{ "country" : "china", "province" : "bj", "userid" : "da"}
{ "country" : "china", "province" : "bj", "userid" : "fa"}
*/

/*分析
*1.可以看到第三组数据和第一组数据一致，不可同时算入处理对象——&gt;应先去重，不可distinct，可以用把三个键重新分组达到去重效果
*2.要求是对country和province同时分组——&gt;应复合分组
*3.将数据的userid数据数量统计
*4.结果肯定会有_id:{字典}的形式，需要美观——&gt;应取出中的字典单独显示，所以采用$_id.键 的形式
*/

//代码
db.集合名.aggregate(
{$group: {_id: {country:"$country",province:"$province",userid:"$userid"} } },
{$group:{ _id: {country:"$_id.country",province:"$_id.province"}, count:{$sum:1} } },
{$project:{ country:"$_id.country",province:"$_id.province",count:1, _id:0 } }
)
//第一行去重
//第二行统计数据
//第三行将_id底下的字典内容取出，再将_id不显示

</code></pre></div></div>]]></content><author><name>Jiaxian Li</name></author><summary type="html"><![CDATA[MongoDB服务器基础篇]]></summary></entry><entry><title type="html">Typora笔记</title><link href="https://jason-space.netlify.app/typora%E7%AC%94%E8%AE%B0/" rel="alternate" type="text/html" title="Typora笔记" /><published>2025-11-19T00:00:00+08:00</published><updated>2025-11-19T00:00:00+08:00</updated><id>https://jason-space.netlify.app/typora%E7%AC%94%E8%AE%B0</id><content type="html" xml:base="https://jason-space.netlify.app/typora%E7%AC%94%E8%AE%B0/"><![CDATA[<p><strong>注意本地的typora打开的笔记在jekyll上运行的方法：</strong></p>
<ul>
  <li>本地的typora笔记的图像地址必须用相对路径</li>
  <li>本地的typora笔记的相对地址前必须加上“/”，否则无法显示图像</li>
  <li>例：本地typora<code class="language-plaintext highlighter-rouge">&lt;img src="typora笔记.assets/image-20250331103930888.png"/&gt;</code>变为jekyll服务器的<code class="language-plaintext highlighter-rouge">&lt;img src="/typora笔记.assets/image-20250331103930888.png"/&gt;</code></li>
</ul>

<p>【注】本地typora源代码正常两行之间会空格才是换行且增加行距；但不希望看到行距：可在源码上去除两行之间的空行从而显示时没有行距</p>

<p>缺点：在jekyll中若两行之间没有空行自动认为是一行：</p>

<p><br /><br /></p>

<h1 id="总结">总结</h1>

<p><code class="language-plaintext highlighter-rouge">#</code>标题
<code class="language-plaintext highlighter-rouge">*</code>斜体
<code class="language-plaintext highlighter-rouge">**</code>加粗
<code class="language-plaintext highlighter-rouge">***</code>斜体加粗
<code class="language-plaintext highlighter-rouge">~</code>删除线
//<code class="language-plaintext highlighter-rouge">~下标~</code>
<code class="language-plaintext highlighter-rouge">=</code>高亮
<code class="language-plaintext highlighter-rouge">^</code>上标</p>

<p><code class="language-plaintext highlighter-rouge">&gt;</code>引用</p>

<p><code class="language-plaintext highlighter-rouge">+/-</code>（中间空格）无序标号
<code class="language-plaintext highlighter-rouge">1.</code>（中间有空格）自动生成有序标号</p>

<p>表格直接右击即可</p>

<p><code class="language-plaintext highlighter-rouge">---</code>是分界线
代码用<code class="language-plaintext highlighter-rouge">保住
代码块：用</code><code class="language-plaintext highlighter-rouge"> 一行 </code><code class="language-plaintext highlighter-rouge">或直接</code>`即可</p>

<p>ctrl+/显示源代码模式</p>

<p>==（1）标题==</p>

<h1 id="一级标题">一级标题</h1>

<h2 id="二级标题">二级标题</h2>

<h3 id="三级标题">三级标题</h3>

<h4 id="四级标题">四级标题</h4>

<h5 id="五级标题">五级标题</h5>

<h6 id="六级标题">六级标题</h6>

<p>==（2）字体==</p>

<p><strong>加粗</strong></p>

<p><em>斜体</em></p>

<p><strong><em>斜体加粗</em></strong></p>

<p><del>删除线</del></p>

<p>==高亮==</p>

<p>我是^上标^</p>

<p>我是~下标~</p>

<p>==（3）列表==</p>

<ul>
  <li>
    <p>一二三四五</p>

    <ul>
      <li>
        <p>上山打老虎</p>

        <ul>
          <li>
            <p>老虎没打到</p>

            <ul>
              <li>打到小松鼠</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<ol>
  <li>
    <p>一二三四五</p>
  </li>
  <li>
    <p>上山打老虎</p>
  </li>
  <li>
    <p>老虎没打到</p>
  </li>
  <li>
    <p>打到小松鼠</p>
  </li>
</ol>

<p>==（4）表格==</p>

<table>
  <tbody>
    <tr>
      <td>Mon</td>
      <td>TUE</td>
      <td>WED</td>
      <td>THU</td>
      <td>FRI</td>
    </tr>
  </tbody>
</table>

<p>| —— | —— | —— | —— | —— |</p>

<table>
  <tbody>
    <tr>
      <td>上山</td>
      <td>上山</td>
      <td>上山</td>
      <td>上山</td>
      <td>上山</td>
    </tr>
  </tbody>
</table>

<table>
  <tbody>
    <tr>
      <td>打老虎</td>
      <td>打老虎</td>
      <td>打老虎</td>
      <td>打老虎</td>
      <td>打老虎</td>
    </tr>
  </tbody>
</table>

<p>==（5）引用==</p>

<blockquote>
  <p>一二三四五</p>
</blockquote>

<blockquote>
  <blockquote>
    <p>上山打老虎</p>
  </blockquote>
</blockquote>

<blockquote>
  <blockquote>
    <blockquote>
      <p>老虎没打到</p>
    </blockquote>
  </blockquote>
</blockquote>

<blockquote>
  <blockquote>
    <blockquote>
      <blockquote>
        <p>打到小松鼠</p>
      </blockquote>
    </blockquote>
  </blockquote>
</blockquote>

<p>==（6）分割线==</p>

<hr />

<p>==（7）代码==</p>

<p><code class="language-plaintext highlighter-rouge">我是代码</code></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
我是代码框

</code></pre></div></div>

<p>==（8）公式==</p>

<ul>
  <li>开启公式编辑</li>
</ul>

<p><img src="/typora笔记.assets/image-20250331103930888.png" alt="image-20250331103930888" style="zoom:50%;" /></p>

<ul>
  <li><strong>公式格式：</strong></li>
</ul>

<p><strong>行内公式</strong>：文字和公式可共同占用一行</p>

<p>格式：<code class="language-plaintext highlighter-rouge">$公式内容$</code></p>

<blockquote>
  <p>举例：$x^{y^z} = (1 + e^x)^{-2xy^w}$是比较难输入的公式。$\iint\limits_D\left(\dfrac{\partial Q}{\partial x}-\dfrac{\partial P}{\partial y}\right){\rm d}x{\rm d}y=\oint\limits_LP{\rm d}x+Q{\rm d}y$也是</p>
</blockquote>

<p><strong>行间公式：</strong>公式单独占一行</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># 格式：</span>
$$
公式内容
$$
</code></pre></div></div>

<p>举例：
\(\iint\limits_D\left(\dfrac{\partial Q}{\partial x}-\dfrac{\partial P}{\partial y}\right){\rm d}x{\rm d}y=\oint\limits_LP{\rm d}x+Q{\rm d}y\)</p>

<p>【补】其他公式编辑方法：</p>

<blockquote>
  <p>https://blog.csdn.net/2302_77250325/article/details/140422947</p>
</blockquote>

<p><img src="/typora笔记.assets/image-20250331104735347.png" alt="image-20250331104735347" style="zoom:50%;" /></p>

<p><img src="/typora笔记.assets/image-20250331104922342.png" alt="image-20250331104922342" style="zoom:50%;" /></p>

<p><img src="/typora笔记.assets/image-20250331104944134.png" alt="image-20250331104944134" style="zoom:50%;" /></p>

<p><img src="/typora笔记.assets/image-20250331105116453.png" alt="image-20250331105116453" style="zoom:50%;" /></p>

<p>==<strong>（9）插入图片</strong>==</p>

<p>设定整个软件的全局设置：复制的图像默认保存在assets文件夹</p>

<p>（否则对于截图到剪切板的图像粘贴到typora中会自动保存在C:\Users\Acer\AppData\Roaming\Typora\typora-user-images）</p>

<p><img src="/typora笔记.assets/image-20250331101740244.png" alt="image-20250331101740244" style="zoom:50%;" /></p>

<p><img src="/typora笔记.assets/image-20250331101751815.png" alt="image-20250331101751815" style="zoom:50%;" /></p>

<p><img src="/typora笔记.assets/image-20250331101724131.png" alt="image-20250331101724131" style="zoom:50%;" /></p>

<p>修改当前笔记保存的文件夹</p>

<p><img src="/typora笔记.assets/image-20250331101538264.png" alt="image-20250331101538264" style="zoom: 50%;" /></p>

<p><img src="/typora笔记.assets/image-20250331101709176.png" alt="image-20250331101709176" style="zoom:50%;" /></p>

<p><img src="/typora笔记.assets/image-20250331101701175.png" alt="image-20250331101701175" style="zoom: 50%;" /></p>

<p>【补】改错：针对不小心将文件保存在混合文件夹，希望将其转存到本地asset文件夹中：</p>

<p>可搜索<code class="language-plaintext highlighter-rouge">C:\Users\Acer\AppData\Roaming\Typora\typora-user-images\</code>字段，然后对图像右键复制到asset文件夹中：</p>

<p><img src="/typora笔记.assets/image-20250331102342677.png" alt="image-20250331102342677" style="zoom:50%;" /></p>]]></content><author><name>Jiaxian Li</name></author><summary type="html"><![CDATA[注意本地的typora打开的笔记在jekyll上运行的方法： 本地的typora笔记的图像地址必须用相对路径 本地的typora笔记的相对地址前必须加上“/”，否则无法显示图像 例：本地typora&lt;img src="typora笔记.assets/image-20250331103930888.png"/&gt;变为jekyll服务器的&lt;img src="/typora笔记.assets/image-20250331103930888.png"/&gt;]]></summary></entry></feed>