一、 MongoDB 简介
为什么要学nosql数据库?
在我们项目当中,或者互联网当中,所产生的数据量是非常庞大的。在大数据量的情况下,对系统的性能而言,在数据库这层是会产生瓶颈的,因为关系型数据库的检索是非常耗时的,进行大量io操作。所以在数据的存储上是有要求的,除了要有关系型数据库以外,还要添加一些非关系型数据库或者叫onsql数据库或者叫内存型数据库。
1 什么是 MongoDB
MongoDB 是一个基于分布式文件存储的数据库。由 C++语言编写。在为 WEB 应用提
供可扩展的高性能数据存储解决方案。
MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功
能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似 json 的 bson 格式,因
此可以存储比较复杂的数据类型。Mongo 最大的特点是它支持的查询语言非常强大,其语
法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功
能,而且还支持对数据建立索引。
2 什么是 NoSQL
NoSQL(NoSQL = Not Only SQL ),意即“不仅仅是 SQL”,是一项全新的数据库革命性运
动,早期就有人提出,发展至 2009 年趋势越发高涨。NoSQL 的拥护者们提倡运用非关系型
的数据存储,相对于铺天盖地的关系型数据库运用,这一概念无疑是一种全新的思维的注入。(nosql数据库会有丢失数据现象)
3 NoSQL 数据库的分类
3.1键值(Key-Value)存储数据库
这一类数据库主要会使用到一个哈希表,这个表中有一个特定的键和一个指针指向特定
的数据。Key/value 模型对于 IT 系统来说的优势在于简单、易部署。但是如果 DBA 只对部
分值进行查询或更新的时候,Key/value 就显得效率低下了。例如: Redis
3.2列存储数据库
这部分数据库通常是用来应对分布式存储的海量数据。键仍然存在,但是它们的特点是
指向了多个列。这些列是由列家族来安排的。如:HBase。
3.3文档型数据库
文档型数据库的灵感是来自于 Lotus Notes 办公软件的,而且它同第一种键值存储相类
似。该类型的数据模型是版本化的文档,半结构化的文档以特定的格式存储,比如 JSON。
文档型数据库可 以看作是键值数据库的升级版,允许之间嵌套键值。而且文档型数据库比
键值数据库的查询效率更高。如:CouchDB, MongoDB. 国内也有文档型数据库 SequoiaDB,
已经开源。
3.4图形(Graph)数据库
图形结构的数据库同其他行列以及刚性结构的 SQL 数据库不同,它是使用灵活的图形
模型,并且能够扩展到多个服务器上。NoSQL 数据库没有标准的查询语言(SQL),因此进行
数据库查询需要制定数据模型。许多 NoSQL 数据库都有 REST 式的数据接口或者查询 API。
如:Neo4J, InfoGrid。
二、 MongoDB 与关系型数据库对比
1 与关系型数据库术语对比
2 存储数据对比
3 RDBMS 与 MongoDB 对应的术语
三、 MongoDB 的数据类型
四、 MongoDB 的下载与安装
1 下载 MongoDB
下载地址:https://www.mongodb.com/download-center/community
2 安装 MongoDB
2.1.1下载 ForLinux 平台的 MongoDB
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191018220545885-2032821303.png)
2.2Linux 安装
在 Linux 平台的 MongoDB 为解压版。我们只要解压 tgz 文件就可以使用。
2.2.1将下载的 tgz 包上传到 Linux 环境中
我将 tgz 包上传到了自己创建的 temp 目录中。该目录位于/root 目录中。
在 Linux 平台的 MongoDB 为解压版。我们只要解压 tgz 文件就可以使用。
2.2.1将下载的 tgz 包上传到 Linux 环境中
我将 tgz 包上传到了自己创建的 temp 目录中。该目录位于/root 目录中。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191018220739997-1489666433.png)
2.2.2解压 tgz 文件
通过 tar 命令对 tgz 文件做解压处理。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191018220808688-321094458.png)
2.2.3移动 MongoDB
我们将解压完的 MongoDB 目录移动到/usr/local 目录中并改名为 mongodb。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191018220846126-1133817481.png)
2.2.4创建数据库目录
MongoDB 的数据存储在 data 目录的 db 目录下,但是这个目录在安装过程不会自动创
建,需要手动创建 data 目录,并在 data 目录中创建 db 目录。data 目录可以创建在任何位置。
本套视频中,我们将 data 目录创建在 mongodb 的根目录下。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191018220917354-1150083146.png)
至此 Linux 平台中的 MongoDB 就已经安装完毕。
3 MongoDB 的启动与关闭
3.1启动 MongoDB
MongoDB 的启动方式分为两种
1)前置启动
2)后置启动
无论哪种启动方式都需要执行 bin 目录中的 mongod 命令。MongoDB 在启动时默认的
查找数据库的路径为/data/db。如果我们数据库路径有变化,需要在该命令中通过--dbpath 参
数来指定 db 目录的路径(该路径可以是绝对路径,也可是相对路径)。
3.1.1前置启动
MongoDB 的默认启动方式为前置启动。所谓前置启动就是 MongoDB 启动进程后会占
用当前终端窗口。
进入到 MongoDB 的 bin 目录。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191018221010299-803983563.png)
执行 bin 目录中的 mongod 命令。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191018221036222-1508367191.png)
由于我们的 db 目录放在 mongodb 的根下,所以在执行该命令时需要通过 --dbpath 参数
指定 db 路径。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191018221109941-1972925743.png)
启动后会在终端中输出一些启动信息。此时终端窗口已被启动进程所占用。我们通过启
动信息可以看到 MongoDB 默认的监听端口为 27017
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191018221132133-1596373069.png)
按 Ctrl+C 可结束启动进程关闭 MongoDB
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191018221154867-1514471283.png)
3.1.2后置启动
所谓后置启动就是以守护进程的方式启动 MongoDB。我们需要在执行 mongod 命令中
添加 --fork 参数。需要注意的是,--fork 参数需要配合着--logpath 或者是--syslog 参数使用。
--logpath 与--syslog 参数是指定 MongoDB 的日志文件。MongoDB 的日志文件可以在系统中的任意位置,本视频中我们在 mongodb 目录下创建 log 目录,在该目录中创建一个名为
mongodb.log 的日志文件。
创建 log 目录
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191018221237784-88424589.png)
在 log 目录中创建 mongodb.log 日志文件
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191018221300767-1631081802.png)
3.1.3常见的启动参数
3.1.4通过配置文件加载启动参数
如果觉得在启动 MongoDB 时给定的参数项太多,那么我们也可以通过配置文件来配置
启动参数,配置文件可以在任意目录中,配置文件的扩展名应为.conf,配置文件中使用
key=value 结构。在执行 MongoDB 时通过--config 参数来指定需要加载的配置文件。
我们在 mongodb 目录下创建一个 etc 目录,在该目录中创建一个名为 mongodb.conf 的
配置文件。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191018221426555-569623505.png)
创建 mongodb.conf 配置文件
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191018221447399-666197146.png)
编辑配置文件,在配置文件中添加配置项:
1)指定 db 路径
2)指定日志文件
3)配置端口
4)配置后端启动
在配置文件中配置启动参数时需要注意的是,在参数前不在加--符号,直接以参数名作
为 key 就可以。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191018221513773-1470791828.png)
通过加载配置文件启动 MongoDB
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191018221537007-195772429.png)
3.1.5配置环境变量
为了能够在任何目录中执行 bin 目录中的命令,我们可以将 bin 目录添加到环境变量中。
修 改 /etc/profile 文 件 , 添 加 export PATH=/usr/local/mongodb/bin:$PATH 。
/usr/local/monogdb/bin 为 MongoDB 的 bin 目录的绝对路径。同学们可根据自己的情况来指定。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191018221611018-1604407112.png)
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191018221645433-1863834769.png)
3.2关闭 MongoDB
3.2.1使用 Ctrl+C 关闭
如果我们的启动方式是前置启动,那么直接使用快捷键 Ctrl+C 就可以关闭 MongoDB。
这种关闭方式会等待当前进行中的的操作完成,所以依然是安全的关闭方式。(不会立即关闭,等所有的操作都做完了,才会去关闭)
3.2.2使用 kill 命令关闭
我们可以通过 Linux 的 kill 命令结束 MongoDB 进程,然后删除 data/db 目录中的
mongod.lock 文件,否则下次无法启动。但是此方法不建议使用,因为会造成数据损坏现象。
3.2.3使用 MongoDB 的函数关闭
在 MongoDB 中提供了两个关闭数据库的函数:
db.shutdownServer()
db.runCommand(“shutdown”)
如上两个方法都需要在 admin 库中执行,并且都是安全的关闭方式。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191019175213332-1309429786.png)
3.2.4使用 mongod 命令关闭 MongoDB
mongod --shutdown --dbpath<数据库路径>
mongod 命令的 shutdown 选项能安全的关闭 MongoDB 服务
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191019175648146-957881146.png)
五、 MongoDB 的用户与权限管理
Mongodb 作为时下最为热门的数据库,那么其安全验证也是必不可少的,否则一个没
有验证的数据库暴露出去,任何人可随意操作,这将是非常危险的。我们可以通过创建用户
的方式来降低风险。
1 Mongodb 用户权限列表
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191019175756767-392027627.png)
2 MongoDB 用户使用
2.1创建 DB 管理用户
mongodb 有一个用户管理机制,简单描述为,有一个管理用户组,这个组的用户是专门
为管理普通用户而设的,暂且称之为管理员。
管理员通常没有数据库的读写权限,只有操作用户的权限, 因此我们只需要赋予管理员
userAdminAnyDatabase 角色即可。
另外管理员账户必须在 admin 数据库下创建。
2.1.1切换到 Admin 库
管理员需要在 admin 数据库下创建,所以我们需要切换到 admin 数据库。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191019175907046-1892724582.png)
2.1.2查看 admin 中的用户
我们可以通过 db.system.users.find()函数来查看 admin 库中的所有用户信息。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191019175942196-1976183919.png)
目前在 admin 库中没有用户,所以查无结果。
2.1.3db.createUser 函数
在 MongoDB 中可以使用 db.createUser({用户信息})函数创建用户。
db.createUser({ user: "<name>", pwd: "<cleartext password>", customData: { <any information> }, roles: [ { role: "<role>", db: "<database>" } | "<role>", ... ] });
1)user:新建用户名。
2)pwd:新建用户密码。
3)customData:存放一些用户相关的自定义数据,该属性也可忽略。
4)roles:数组类型,配置用户的权限。
2.1.4创建管理员用户
我们现在需要在 admin 库中创建一个名为 bjsxt 的管理员用户,密码为 bjsxtpwd。
db.createUser({user:'bjsxt',pwd:'bjsxtpwd',roles:[{role:'userAdminAnyDatabase',db:'admin'}])
创建成功后会看到如下提示:
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191019180121694-1735348566.png)
2.1.5重启 MongoDB
在管理员账户创建完成后,我们需要重新启动 MongoDB,并开启验证。
重新启动函数:db.shutdownServer()。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191019180152373-1488791661.png)
2.1.6使用权限方式启动 MongoDB
在默认的情况下 MongoDB 是不开启用户认证的。如果我们添加用户,那么需要开启用
户认证机制。通过修改 mongodb.conf 配置文件,在文件中添加 auth=true 即可。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191019180227496-1194226969.png)
2.1.7用户认证
创建管理员后,需要认证方可使用该用户,否则会提示需要认证。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191019180302762-37838590.png)
2.2创建普通用户
普通用户由管理员创建。通常需要指定操作某个数据库。
2.2.1需求
我们创建一个 sxt 数据库,给这个数据库添加一个用户,用户名为 itsxt,密码为 itsxtpwd。
并授予该用户对 sxt 数据库进行读写操作的权限。
2.2.2使用管理员用户登录
普通用户需要由管理员创建并授权。所以,我们首先做的就是用管理员账户登录数据库。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191019180406083-1565703564.png)
2.2.3创建 sxt 数据库
use 命令切换数据库时如果该库不存在,那么则会创建该数据库。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191019180435976-1531607617.png)
2.2.4创建普通用户
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191019180456893-1929668559.png)
2.2.5使用普通用户
打开一个新的客户端。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191019180522535-1471897210.png)
2.2.6切换到 sxt 数据库
由于我们是在 sxt 数据库中创建的 itsxt 用户,所以需要先切换到 sxt 库。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191019180556139-1748601603.png)
2.2.7登录普通用户
如果我们不登录会发现无法对该数据库进行插入操作。因为缺少用户认证。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191019180626385-1283170543.png)
通过认证函数对用户进行登录认证。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191019180703573-1357165072.png)
认证成功后操作通过该用户操作 sxt 库。该用户对 sxt 库具备读写操作。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191019180728848-687967562.png)
2.3更新用户角色
如果我们需要对已存在的用户的角色做修改,那么我们可以使用 db.updateUser()函数来
更新用户角色。注意,该函数需要当前用户具有 userAdminAnyDatabase 或者更高的权限。
2.3.1更新角色语法格式
db.updateUser("用户名", {"roles":[{"role":"角色名称"},{"更新项 2":"更新内容"}]})
2.3.2需求
目前 bjsxt 管理员用户只具备 userAdminAnyDatabase 用户管理角色,我们为该用户添加
一个 dbAdminAnyDatabase 数据库管理角色。
2.3.3更新角色
db.updateUser("bjsxt",{roles : [{"role" : "userAdminAnyDatabase","db" : "admin"},{"role" :
"dbAdminAnyDatabase","db" : "admin"}]})
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021192815011-760842103.png)
2.3.4查看用户信息
通过 show users 命令查看到 bjsxt 用户的角色已经发生改变。
2.4更新用户密码
更新用户密码有两种方式:
- 1)使用 db.updateUser()函数更新密码。
- 2)使用 db.changeUserPassword()函数更新密码
2.4.1更新密码方式一
使用 db.upateUser()函数将 bjsxt 用户的密码修改为 sxt
2.4.1.1 语法格式
db.updateUser("用户名",{"pwd":"新密码"})
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021193051728-2018867304.png)
如果未提示任何信息则表示更新成功。退出当前客户端重新连接认证即可。
重新使用 bjsxt 用户登录
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021193123582-1479135312.png)
2.4.2更新密码方式二
使用 db.changeUserPassword()函数将 bjsxt 用户的密码修改为 sxtpwd。
2.4.2.1 语法格式
db.changeUserPassword("用户名","新密码")
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021193230859-1529240808.png)
如果未提示任何信息则表示更新成功。退出当前客户端重新连接认证即可。
重新使用 bjsxt 用户登录
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021193316391-1969481542.png)
2.5删除用户
通过 db.dropUser()函数可删除指定用户。删除成功后会返回 true。在删除用户时需要切
换到创建用户时所指定的数据库中才可以删除。注意:需要使用具有 userAdminAnyDatabse
角色管理员用户才可以删除其他用户。
2.5.1需求
我们使用 db.dropUser()函数将 itsxt 用户删除。
2.5.2切换数据库
itsxt 用户在 sxt 数据库中,所以需要先切换到 sxt 数据库。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021193442591-1241919430.png)
2.5.3通过函数删除用户
我们可以看到,该函数返回了 true,表示删除成功。
六、 MongoDB 的数据库操作
1 创建数据库
在 MongoDB 中创建数据库的命令使用的是 use 命令。该命令有两层含义:
1)切换到指定数据库。
2)如果切换的数据库不存在,则创建该数据库。
我们使用 use 命令创建一个名为 sxttest 的数据库。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021193621218-1944804828.png)
2 查看所有数据库
我们可以通过 show dbs 命令查看当前 MongoDB 中的所有数据库。
如果开启了用户认证,则需要先登录方可查看到结果,否则不显示任何信息。如果使用
的是具备数据库管理员角色的用户,那么则可以看到 MongoDB 中的所有数据库,如果使用
的普通用户登录的那么只能查询到该用户所拥有的数据库。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021193705662-1066774581.png)
使用普通用户登录查询数据库。
我们在 sxt 数据库中创建一个只具备读写权限的普通用户。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021193810329-1873593860.png)
3 删除数据库
在 MongoDB 中使用 db.dropDatabase()函数来删除数据库。在删除数据库之前,需要使用具备 dbAdminAnyDatabase 角色的管理员用户登录,然后切换到需要删除的数据库,执行
db.dropDatabase()函数即可。删除成功后会返回一个{ "ok" : 1 }的 JSON 字符串。
我们现在将刚刚创建的 sxttest 删除。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021193931723-1136663075.png)
七、 MongoDB 的集合操作
MongoDB 中的集合是一组文档的集,相当于关系型数据库中的表。
1 创建集合
MongoDB 使用 db.createCollection()函数来创建集合。
语法格式:db.createCollection(name, options)。
name: 要创建的集合名称。
options: 可选参数, 指定有关内存大小及索引的选项。
options 可以是如下参数。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021194021804-1643540652.png)
1.1使用默认集合
在 MongoDB 中,我们也可以不用创建集合,当我们插入一些数据时,会自动创建集合,
并且会使用数据库的名字作为集合的名称。
创建一个新数据库,名为 develop
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021194114910-205555719.png)
1.2创建不带参数的集合
我们也可以根据自己的情况创建集合。在 develop 数据库中创建一个名为 dev 的集合,
该集合创建时不指定任何参数。如果开启认证,则需要使用具有数据库管理员权限的用户来
创建集合。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021194240524-1401424311.png)
1.3创建带参数的集合
在 develop 数据库中创建一个名为 dev2 的固定集合,整个集合空间大小为 2000000kb,
文档最大个数为 1000。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021194326250-1884210852.png)
2 查看集合
如果要查看已有集合,可以使用 show collections 或 show tables 命令。
2.1show collections
2.2show tables
3 删除集合
如果我们要删除集合,需要先切换到需要删除集合所在的数据库,使用 drop()函数删除
集合即可。
删除集合的语法格式为:db.集合名称.drop()。
删除 dev2 集合
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021202336046-392901077.png)
八、 MongoDB 的文档操作
在 MongoDB 中文档是指多个键及其关联的值有序地放置在一起就是文档,其实指的就
是数据,也是我们平时操作最多的部分。
MongoDB 中的文档的数据结构和 JSON 基本一样。所有存储在集合中的数据都是
BSON 格式。
BSON 是一种类似 JSON 的二进制形式的存储格式,是 Binary JSON 的简称。
1 插入文档
1.1插入单个文档
1.1.1insert 函数
语法格式为:db.COLLECTION_NAME.insert(document)。
向 dev 集合中插入单个文档。
{title:'北京尚学堂',description:'程序员的摇篮',url:'www.bjsxt.com',tags:['java','大数据','python']}
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021202504128-1107960988.png)
1.1.2save 函数
向 dev 集合中插入单个文档。
{title:'百战程序员',description:'身经百战,高薪相伴',url:'www.itbaizhan.cn',tags:['javaWeb实战','数据库实战','微服务实战']}
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021202616437-421325633.png)
查看文档
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021202637808-1499123525.png)
1.1.3insertOne 函数
在 MongoDB3.2 以后的版本中,提供了 insertOne()函数用于插入文档。
向 dev 集合中插入单个文档。
{title:' 尚 学 堂 大 数 据 ',description:' 培 养 大 数 据 人 才 的 摇 篮',url:'www.bjsxt.com',tags:['hadoop','spark','Hbase']}
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021202747655-112663890.png)
1.2插入多个文档
向集合中批量插入多个文档时,需要使用数组来存放文档。
语法格式:db.COLLECTION_NAME.insert([{},{},{}.....])。
1.2.1insert 或者 save 函数
向 dev 集合中批量插入多个文档
[{title:'java',tags:['JavaSE','JavaEE','JavaME']},{title:'ORM',tags:['Mybatis','Hibernate']},{title:'Spring',tags:['SpringMVC','SpringBoot','SpringCloud']}]
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021202838697-1391104444.png)
查看文档
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021202900091-670901302.png)
1.2.2insertMany 函数
在 MongoDB3.2 以后的版本中,提供了 insertMany 函数用于插入文档。
语法格式:db.COLLECTION_NAME.insertMany([{},{},{},.....])。
向 dev 集合中批量插入多个文档
[{title:'Web',tags:['JSP','Servlet']},{title:'RPC',tags:['RMI','Dubbo']},{title:'DataBase',tags:['Oracle','MySQL']}]
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021202953477-377010470.png)
1.3通过变量插入文档
Mongo Shell 工具允许我们定义变量。所有的变量类型为 var 类型。也可忽略变量类型。
变量中赋值符号后侧需要使用小括号来表示变量中的值。我们可以将变量作为任意插入文档
的函数的参数。
语法格式:变量名=({变量值})
1.3.1通过变量插入单个文档
定义变量
document=({title:'SpringCloud',tags:['Spring Cloud Netflix','Spring Cloud Security','SpringCloud Consul']})
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021203054452-1639320688.png)
1.3.2通过变量插入多个文档
我们也可以在变量中定义多个文档。
语法结构:变量名=([{},{},{},....])
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021203149479-877828555.png)
插入文档
我们现在将多个文档放入到了一个变量中,所以在插入数据时,可直接使用插入单个文
档的函数。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021203231489-1088594345.png)
2 更新文档
MongoDB 通过 update 函数或者 save 函数来更新集合中的文档。
2.1update 函数
update() 函数用于更新已存在的文档。
语法格式:db.COLLECTION_NAME.update({查询条件},{更新内容},{更新参数(可选)})
将 Spring Data 修改为 SpringData
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021203338925-1102472378.png)
2.2更新操作符
2.2.1$set 操作符
$set 操作符:用来指定一个键并更新键值,若键不存在并创建。
语法格式:db.COLLECTION_NAME.update({查询条件},{更新操作符:{更新内容}})
将 Spring Security 修改为 SpringSecurity。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021203438245-1532715158.png)
修改后的结果
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021203508037-2043505398.png)
使用$set 在 title 为 SpringData 的文档中添加一个属性为 num 值为 1。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021203529399-1525475043.png)
批量更新
在更新文档时,可以使用 multi 参数实现批量更新。
添加测试数据
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021203620688-2068242844.png)
将 title 为 dev 的文档的 size 更新为 500
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021203647716-160655852.png)
2.2.2$inc 操作符
$inc 操作符:可以对文档的某个值为数字型(只能为满足要求的数字)的键进行增减的操作。
将 title 为 SpringData 的文档中的 num 值递增 1。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021203750606-213023469.png)
4 查询文档
4.1find()函数
在 MongoDB 中可以使用 find()函数查询文档。
语法格式为:find({查询条件(可选)},{指定投影的键(可选)})
如果未给定参数则表示查询所有数据。
pretty()函数可以使用格式化的方式来显示所有文档。
查询 dev 集合中的所有数据并格式化显示。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021214139367-1741149136.png)
使用 getIndexSpecs()函数查看当前 dev 集合中的索引
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021221103412-180609138.png)
中提取数据,这是非常快速的数据查询。
由于我们的索引中不包括 _id 字段,_id 在查询中会默认返回,我们可以在 MongoDB
的查询结果集中排除它。
8.9查询计划
在 MongoDB 中通过 explain()函数启动执行计划,我们可以使用查询计划分析索引的使
用情况,可通过查看详细的查询计划来决定如何优化。
语法结构:db.COLLECTION_NAME.find().explain()
删除 dev 集合中的所有索引。通过查询计划查看查询 size 键的值大于 200 的查询结果
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021221711241-1254556867.png)
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191021221728323-1817127557.png)
比如需要查询:
db.test.find({"username":"kaka", "age": {$gt: 30}})
那么复合索引应该这样创建:
db.test.ensureIndex({"username":1, "age":-1})
8.10.1.3 查询时尽可能仅查询出索引字段
有时候仅需要查询少部分的字段内容,而且这部分内容刚好都建立了索引,那么尽可能
只查询出这些索引内容,需要用到的字段显式声明(_id 字段需要显式忽略!)。因为这些
数据需要把原始数据文档从磁盘读入内存,造成一定的损耗。
比如说我们的表有三个字段:
name, age, mobile
索引是这样建立的:
db.stu.createIndex({"name":1,"age":-1})
我们仅需要查到某个用户的年龄(age),那可以这样写:
db.stu.find({"name":"kaka"}, {"_id":0, "age":1})
注意到上面的语句,我们除了”age”:1 外,还加了”_id”:0,因为默认情况下,_id
都是会被一并查询出来的,当不需要_id 的时候记得直接忽略,避免不必要的磁盘操作。
8.10.1.4 对现有的数据大表建立索引的时候,采用后台运行方式
在对数据集合建立索引的过程中,数据库会停止该集合的所有读写操作,因此如果建立
索引的数据量大,建立过程慢的情况下,建议采用后台运行的方式,避免影响正常业务流程。
db.stu.ensureIndex({"name":1,"age":-1},{"background":true})
8.11索引限制
8.11.1 额外开销
每个索引占据一定的存储空间,在进行插入,更新和删除操作时也需要对索引进行操作。
所以,如果你很少对集合进行读取操作,建议不使用索引。
8.11.2 内存使用
由于索引是存储在内存(RAM)中,你应该确保该索引的大小不超过内存的限制。
如果索引的大小大于内存的限制,MongoDB 会删除一些索引,这将导致性能下降。
8.11.3 查询限制
索引不能被以下的查询使用:
正则表达式(最左匹配除外)及非操作符,如 $nin, $not, 等。
算术运算符,如 $mod, 等。
所以,检测你的语句是否使用索引是一个好的习惯,可以用 explain 来查看。8.11.4 最大范围
集合中索引不能超过 64 个
索引名的长度不能超过 128 个字符
一个复合索引最多可以有 31 个字段
8.12正则查询
MongoDB 中查询条件也可以使用正则表达式作为匹配约束。
语法格式:db.COLLECTION_NAME.find({字段名:正则表达式});
或
db.COLLECTION_NAME.find({字段名:{$regex:正则表达式,$options:正则选项}});
正则表达式格式:/xxx/
正则选项:
i - 不区分大小写以匹配大小写的情况。
m - 多行查找,如果内容里面不存在换行符号(例如
)或者条件上没有(start/end),
该选项没有任何效果
x - 设置 x 选项后,正则表达式中的非转义的空白字符将被忽略。需要$regex 与$options
语法
s - 允许点字符(即.)匹配包括换行符在内的所有字符。需要$regex 与$options 语法
i,m,x,s 可以组合使用。
查询 dev 集合中 title 字段以'S'开头的数据
db.dev.find({title:/^S/})
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191023220512923-1543093238.png)
查询 dev 集合中 title 字段以'g'结尾的数据
db.stu.find({title:/g$/})
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191023220558056-1316032859.png)
9 MongoDB 聚合查询
在 MongoDB 中我们可以通过 aggregate()函数来完成一些聚合查询,aggregate()函数主
要用于处理诸如统计,平均值,求和等,并返回计算后的数据结果。
语法格式:
db.COLLECTION_NAME.aggregate([{$group:{_id:"$分组键名","$分组键名",.....,别名:{聚合
运算:"$运算列"}}},{条件筛选:{键名:{运算条件:运算值}}}])
常见的 mongo 的聚合操作和 mysql 的查询做类比
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191023220843449-2054772000.png)
9.1求和 - $sum
查询 dev 集合中一共有多少个文档。相当于 sql 语句:SELECT count(*) AS count FROM dev
db.dev.aggregate([{$group:{_id:null,count:{$sum:1}}}])
$group:分组,代表聚合的分组条件
_id:分组的字段。相当于 SQL 分组语法 group by column_name 中的 column_name 部分。
如果根据某字段的值分组,则定义为_id:'$字段名'。所以此案例中的 null 代表一个固定的字
面值'null'。
count:返回结果字段名。可以自定义,类似 SQL 中的字段别名。
$sum:求和表达式。相当于 SQL 中的 sum()。
1:累加值。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191023220930090-1242452497.png)
9.8.3$project-算术运算
在$project 中我们可以通过 MongoDB 的算数作符对投影的内容做运算处理。
查询 dev 集合中数据,显示 title 和 size 字段,为 size 字段数据做加 1 操作,显示字段
命名为 New_Size。
db.dev.aggregate([{$project:{_id:0,title:1,New_Size:{$add:["$size",1]}}}])
New_Size:{$add:["$size",1]}:在查询结果中,对size的值做加1处理,并命名为New_Size。
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191023221441120-1334374768.png)
显示自定义日期格式
db.dev.aggregate([{$match:{name:"admin"}},{$project:{ 年 份 :{$year:"$birth"},
月份 :{$month:"$birth"}, 日 :{$dayOfMonth:"$birth"}, 时 :{$hour:"$birth"}, 分 :{$minute:"$birth"},
秒:{$second:"$birth"},毫秒:{$millisecond:"$birth"},星期:{$dayOfWeek:"$birth"},全年的第几
周 :{$week:"$birth"}, 全 年 中 的 第 几 天 :{$dayOfYear:"$birth"}, 自 定 义 日 期 格式:{$dateToString:{format:"%Y 年%m 月%d 日 %H:%M:%S",date:"$birth"}}}}])
{$dateToString:{format:"%Y 年%m月%d 日 %H:%M:%S",date:"$birth"}:自定义日期格式
具体格式如下:
![](https://img2018.cnblogs.com/blog/1504650/201910/1504650-20191023222651007-1219655135.png)
在 POM 文件中添加 MongoDB 驱动坐标
<!--添加 MongoDB 驱动坐标--> <dependencies> <!-- https://mvnrepository.com/artifact/org.mongodb/mongo-java -driver --> <dependency> <groupId>org.mongodb</groupId> <artifactId>mongo-java-driver</artifactId> <version>3.8.2</version> </dependency> </dependencies>
1.2创建 MongoDB 连接
封装 MongoDBUtil
public class MongoDBUtil { private static MongoClient client = null; static{ if(client == null){ client = new MongoClient("192.168.70.156",27017); } } //获取 MongoDB 数据库 public static MongoDatabase getDatabase(String dbName){ return client.getDatabase(dbName); } //获取 MongoDB 中的集合 public static MongoCollection getCollection(String dbName,String collName){ MongoDatabase database = getDatabase(dbName); return database.getCollection(collName); } }
1.3创建 MongoDB 的认证连接
封装 MongoDBAuthUtil
/** * 创建 MongoDB 拦截-使用用户认证 */ public class MongoDBAuthUtil { private static MongoClient client = null; static{ if(client == null){ //创建一个封装用户认证信息 MongoCredential credential = MongoCredential.createCredential("itsxt","develop","itsxt pwd".toCharArray()); //封装 MongoDB 的地址与端口 ServerAddress address = new ServerAddress("192.168.70.156",27017); client = new MongoClient(address, Arrays.asList(credential)); } } //获取 MongoDB 数据库 public static MongoDatabase getDatabase(String dbName){ return client.getDatabase(dbName); } //获取 MongoDB 中的集合 public static MongoCollection getCollection(String dbName, String collName){ MongoDatabase database = getDatabase(dbName); return database.getCollection(collName); } }
1.4创建 MongoDB 的池连
封装 MongoDBPoolUtil
/** * 使用池连的方式获取连接 */ public class MongoDBPoolUtil { private static MongoClient client = null; static{ if(client == null){ MongoClientOptions.Builder builder = new MongoClientOptions.Builder(); builder.connectionsPerHost(10);//每个地址的最大连 接数 builder.connectTimeout(5000);//连接超时时间 builder.socketTimeout(5000);//设置读写操作超时时间 ServerAddress address = new ServerAddress("192.168.70.156",27017); client = new MongoClient(address,builder.build()); } } //获取 MongoDB 数据库 public static MongoDatabase getDatabase(String dbName){ return client.getDatabase(dbName); } //获取 MongoDB 中的集合 public static MongoCollection getCollection(String dbName, String collName){ MongoDatabase database = getDatabase(dbName); return database.getCollection(collName); } }
1.5创建 MongoDB 的认证池连
封装 MongoDBAuthPoolUtil
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 支持用户认证的池连 */ public class MongoDBAuthPoolUtil { private static MongoClient client = null; static{ if(client == null){ MongoClientOptions.Builder builder = new MongoClientOptions.Builder(); builder.connectionsPerHost(10);//每个地址的最大连 接数 builder.connectTimeout(5000);//连接超时时间 builder.socketTimeout(5000);//设置读写操作超时时间 MongoCredential credential = MongoCredential.createCredential("itsxt","develop","itsxt pwd".toCharArray()); ServerAddress address = new ServerAddress("192.168.70.156",27017); client = new MongoClient(address,credential,builder.build()); } } //获取 MongoDB 数据库 public static MongoDatabase getDatabase(String dbName){ return client.getDatabase(dbName); } //获取 MongoDB 中的集合 public static MongoCollection getCollection(String dbName, String collName){ MongoDatabase database = getDatabase(dbName); return database.getCollection(collName); } }
2 操作集合
2.1创建集合
//创建集合 public static void createCollection(String dbName,String collName){ MongoDatabase database = getDatabase(dbName); database.createCollection(collName); }
2.2获取集合
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//获取 MongoDB 中的集合 public static MongoCollection getCollection(String dbName, String collName){ MongoDatabase database = getDatabase(dbName); return database.getCollection(collName); }
2.3删除集合
//删除集合 public static void dropCollection(MongoCollection coll){ coll.drop(); }
3 操作文档
3.1添加文档
3.1.1添加单个文档
/** * 添加单个文档 */ public void inesrtSingleDocument(){ //获取集合 MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); // {}---->Document //append(String key,Object value)---->{key:value} Document docu = new Document(); docu.append("username","lisi").append("userage",26).appen d("userdesc","Very Good").append("userlike", Arrays.asList(new String[]{"Music","Sport"})); collection.insertOne(docu); }
3.1.2添加多个文档
/** * 文档的批量添加 */ public void insertManyDocument(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); List<Document> list = new ArrayList<>(); for(int i=0;i<5;i++){ Document docu = new Document(); docu.append("username","zhangsan"+i); docu.append("userage",20+i); docu.append("userdesc","OK"+i); docu.append("userlike",Arrays.asList(new String[]{"Music","Sport"})); list.add(docu); } collection.insertMany(list); }
3.2更新文档
3.2.1更新单个文档单个键
/** * 更新单个文档单个键 */ public void updateSingleDocumentSingleKey(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); //更新文档 //Filters 封装了条件的一个工具类{$set:{userage:28}} collection.updateOne(Filters.eq("username","lisi"),new Document("$set",new Document("userage",28))); }
3.2.2更新单个文档多个键
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 更新单个文档多个键 */ public void updateSingleDocumentManyKey(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); collection.updateOne(Filters.eq("username","zhangsan0"),n ew Document("$set",new Document("userage",18).append("userdesc","Very Good"))); }
3.2.3更新多个文档中的单个键
/** * 更新多个文档单个键 */ public void updateManyDocumentSingleKey(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); collection.updateMany(Filters.ne("username",null),new Document("$set",new Document("userdesc","Very Good"))); }
3.2.4更新多个文档中的多个键
/** * 更新多个文档多个键 */ public void updateManyDocumentManyKey(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); collection.updateMany(Filters.ne("username",null),new Document("$set",new Document("userdesc","OK").append("userage",20))); }
3.2.5更新文档中的数组
/** * 更新文档中的数组 * {$push:{}} */ public void updateDocumentArray(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); collection.updateOne(Filters.eq("username","lisi"),new Document("$push",new Document("userlike","Art"))); }
3.3查询文档
3.3.1查询全部文档
/** * 查询全部文档 */ public void selectDocumentAll(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); //返回的是一个文档的迭代器 FindIterable<Document> iterable = collection.find(); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); System.out.println(docu.get("username")+" "+docu.get("us erage")+" "+docu.get("userdesc")+" "+docu.get("userlike ")); } }
3.3.2根据_id 查询文档-$eq
/** * 根据_id 查询文档 */ public void selectDocumentById(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); FindIterable<Document> iterable = collection.find(Filters.eq("_id",new ObjectId("5d398cd64b022206d87d168e"))); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); System.out.println(docu.get("username")+" "+docu.get("us erage")+" "+docu.get("userdesc")+" "+docu.get("userlike ")); } }
3.3.3查询多个文档-$gt
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 根据年龄查询文档,条件是年龄大于 19 */ public void selectDocumentConditionByGt(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); FindIterable iterable = collection.find(Filters.gt("userage",19)); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); System.out.println(docu.get("username")+" "+docu.get("us erage")+" "+docu.get("userdesc")+" "+docu.get("userlike ")); } }
3.3.4查询多个文档-$type
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 根据年龄查询文档,添加是年龄的值是整数类型(number) */ public void selectDocumentConditionByType(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); FindIterable iterable = collection.find(Filters.type("userage","number")); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); System.out.println(docu.get("username")+" "+docu.get("us erage")+" "+docu.get("userdesc")+" "+docu.get("userlike ")); } }
3.3.5查询多个文档-$in
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 查询用户的名字为 zhangsan1,zhangsan2 */ public void selectDocumentConditionByIn(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); FindIterable iterable = collection.find(Filters.in("username","zhangsan1","zhangs an2")); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); System.out.println(docu.get("username")+" "+docu.get("us erage")+" "+docu.get("userdesc")+" "+docu.get("userlike ")); } }
3.3.6查询多个文档-$nin
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 查询用户的名字不是 zhangsan1,zhangsan2 */ public void selectDocumentConditionByNin(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); FindIterable iterable = collection.find(Filters.nin("username","zhangsan1","zhang san2")); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); System.out.println(docu.get("username")+" "+docu.get("us erage")+" "+docu.get("userdesc")+" "+docu.get("userlike ")); } }
3.3.7查询多个文档-$regex
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 查询用户的名字是 z 开头 2 结尾的。 */ public void selectDocumentConditionByRegex(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); FindIterable iterable = collection.find(Filters.regex("username", Pattern.compile("^z.*2$"))); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); System.out.println(docu.get("username")+" "+docu.get("us erage")+" "+docu.get("userdesc")+" "+docu.get("userlike ")); } }
3.3.8逻辑运算符-$and
/** * 查询用户 username 是 zhangsan1 并且年龄为 20 岁的用户 */ public void selectDocumentConditionUseAnd(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); FindIterable iterable = collection.find(Filters.and(Filters.eq("username","zhangs an1"),Filters.eq("userage",21),Filters.eq("userdesc","Ver y Good"))); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); System.out.println(docu.get("username")+" "+docu.get("us erage")+" "+docu.get("userdesc")+" "+docu.get("userlike ")); } }
3.3.9逻辑运算符-$or
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 查询用户要求 username 是 list,或者 userage 是 20 或者 userdesc 是 Very Good */ public void selectDocumentConditionUseOr(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); FindIterable iterable = collection.find(Filters.or(Filters.eq("username","lisi"), Filters.eq("userage",20),Filters.eq("userdesc","Very Good"))); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); System.out.println(docu.get("username")+" "+docu.get("us erage")+" "+docu.get("userdesc")+" "+docu.get("userlike ")); } }
3.3.10 逻辑运算符-$and 与$or 联合使用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 查询文档中 username 为 lisi 并且年龄为 20 岁,或者 userdesc 为 Very Good */ public void selectDocumentConditionAndOr(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); FindIterable iterable = collection.find(Filters.or(Filters.and(Filters.eq("userna me","lisi"),Filters.eq("userage",20)),Filters.eq("userdes c","Very Good"))); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); System.out.println(docu.get("username")+" "+docu.get("us erage")+" "+docu.get("userdesc")+" "+docu.get("userlike ")); } }
3.3.11 查询文档-排序处理
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 查询文档中 username 是 z 开头的,根据 username 对结果做降序排序。1 升序排序, -1 降序排序规则 $sort:{username,-1} */ public void selectDocumentSorting(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); FindIterable iterable = collection.find(Filters.regex("username",Pattern.compile( "^z"))).sort(new Document("username",-1)); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); System.out.println(docu.get("username")+" "+docu.get("us erage")+" "+docu.get("userdesc")+" "+docu.get("userlike ")); } }
3.4日期操作
3.4.1插入系统当前日期
/** * 插入系统当前日期 */ public void insertDocumentSystemDate(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); Document docu = new Document(); docu.put("username","wangwu"); docu.put("userage",22); docu.put("userdesc","Very Good"); docu.put("userlike", Arrays.asList(new String[]{"Music","Art"})); docu.put("userbirth",new Date()); collection.insertOne(docu); }
3.4.2插入指定日期
创建日期处理工具类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class DateUtil { /** * Date To String */ public static String dateToString(String pattern, Date date){ SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern); return simpleDateFormat.format(date); } /** * String To Date */ public static Date stringToDate(String pattern, String date){ SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern); Date d = null; try{ d = simpleDateFormat.parse(date); }catch(Exception e){ e.printStackTrace(); } return d; } }
添加指定日期
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 插入指定日期 */ public void insertDocumentCustoDate(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); Date date= DateUtil.stringToDate("yyyy-MM-dd HH:mm:ss","2019-05-01 13:32:13"); Document docu = new Document(); docu.put("username","zhaoliu"); docu.put("userage",24); docu.put("userdesc","Very Good"); docu.put("userlike", Arrays.asList(new String[]{"Music","Art"})); docu.put("userbirth",date); collection.insertOne(docu); }
3.4.3查询日期-$eq
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 插入日期:查询用的生日为 2019-05-01 13:32:13 的用户信息 */ public void selectDocumentDateUseEq(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); Date date = DateUtil.stringToDate("yyyy-MM-dd HH:mm:ss","2019-05-01 13:32:13"); FindIterable iterable = collection.find(Filters.eq("userbirth",date)); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); String temp = DateUtil.dateToString("yyyy-MM-dd HH:mm:ss",(Date) docu.get("userbirth")); System.out.println(docu.get("username")+" "+docu.get("us erage")+" "+docu.get("userdesc")+" "+docu.get("userlike ")+" "+temp); } }
3.4.4查询日期-$gt
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 查询日期:查询用的生日大于 2019-01-01 00:00:00 的用户信息 */ public void selectDocumentDateUseGt(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); Date date = DateUtil.stringToDate("yyyy-MM-dd HH:mm:ss","2019-01-01 00:00:00"); FindIterable iterable = collection.find(Filters.gt("userbirth",date)); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); String temp = DateUtil.dateToString("yyyy-MM-dd HH:mm:ss",(Date) docu.get("userbirth")); System.out.println(docu.get("username")+" "+docu.get("us erage")+" "+docu.get("userdesc")+" "+docu.get("userlike ")+" "+temp); } }
3.5聚合操作
3.5.1聚合操作-计算文档总数-$sum
需求:查询集合中的文档数量
Mongo Shell:db.dev.aggregate([{$group:{_id:null,count:{$sum:1}}}])
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 需求:查询集合中的文档数量 Mongo Shell:db.dev.aggregate([{$group:{_id:null,count:{$sum:1}} }]) */ public void selectDocumentAggregateCount(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","dev"); Document sum = new Document(); sum.put("$sum",1); Document count = new Document(); count.put("_id",null); count.put("count",sum); Document group = new Document(); group.put("$group",count); List<Document> list = new ArrayList<>(); list.add(group); AggregateIterable iterable = collection.aggregate(list); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); System.out.println(docu.get("count")); } }
3.5.2聚合操作-计算值的总和-$sum
需求:查询集合中所有 size 键中的值的总和
Mongo Shell:db.dev.aggregate([{$group:{_id:null,totalSize:{$sum:"$size"}}}])
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 需求:查询集合中所有 size 键中的值的总和 Mongo Shell:db.dev.aggregate([{$group:{_id:null,totalSize:{$sum :"$size"}}}]) */ public void selectDocumentAggregateSum(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","dev"); Document sum = new Document(); sum.put("$sum","$size"); Document totalSize = new Document(); totalSize.put("_id",null); totalSize.put("totalSize",sum); Document group = new Document(); group.put("$group",totalSize); List<Document> list = new ArrayList<>(); list.add(group); AggregateIterable iterable = collection.aggregate(list); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); System.out.println(docu.get("totalSize")); } }
3.5.3聚合操作-在分组中计算值的总和-$sum
需求:对 title 进行分组,计算每组中的 size 的总和
Mongo Shell:db.dev.aggregate([{$group:{_id:"$title",totalSize:{$sum:"$size"}}}])
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 需求:对 title 进行分组,计算每组中的 size 的总和 Mongo Shell:db.dev.aggregate([{$group:{_id:"$title",totalSize:{ $sum:"$size"}}}]) */ public void selectDocumentAggregateGroupBySum(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","dev"); Document sum= new Document(); sum.put("$sum","$size"); Document totalSize = new Document(); totalSize.put("_id","$title"); totalSize.put("totalSize",sum); Document group = new Document(); group.put("$group",totalSize); List<Document> list = new ArrayList<>(); list.add(group); AggregateIterable iterable = collection.aggregate(list); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); System.out.println(docu.get("totalSize")); } }
3.5.4聚合操作-分组前的数据过滤-$match
需求:查询 dev 集合有多少文档的 size 大于 200。
Mongo Shell:
db.dev.aggregate([{$match:{size:{$gt:200}}},{$group:{_id:null,totalSize:{$sum:1}}}])
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 需求:查询 dev 集合有多少文档的 size 大于 200。 Mongo Shell: db.dev.aggregate([{$match:{size:{$gt:200}}},{$group:{_id: null,totalSize:{$sum:1}}}]) */ public void selectDocumentAggregateGroupByWhere(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","dev"); Document gt = new Document(); gt.put("$gt",200); Document size = new Document(); size.put("size",gt); Document match = new Document(); match.put("$match",size); Document sum = new Document(); sum.put("$sum",1); Document totalSize = new Document(); totalSize.put("_id",null); totalSize.put("totalSize",sum); Document group = new Document(); group.put("$group",totalSize); List<Document> list = new ArrayList<>(); list.add(match); list.add(group); AggregateIterable iterable = collection.aggregate(list); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); System.out.println(docu.get("totalSize")); } }
3.5.5聚合操作-分组后的数据过滤-$match
需求:查询 dev 集合,根据 title 分组计算出每组的 size 的总和,并过滤掉总和小于 200
的文档。
Mongo Shell:
db.dev.aggregate([{$group:{_id:"$title",totalSize:{$sum:"$size"}}},{$match:{totalSize:{$gt:200}}}])
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 需求:查询 dev 集合,根据 title 分组计算出每组的 size 的总和,并过 滤掉总和小于 200 的文档。 Mongo Shell: db.dev.aggregate([{$group:{_id:"$title",totalSize:{$sum:" $size"}}},{$match:{totalSize:{$gt:200}}}]) */ public void selectDocumentAggregateGroupByHaving(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","dev"); Document sum = new Document(); sum.put("$sum","$size"); Document totalSize = new Document(); totalSize.put("_id","$title"); totalSize.put("totalSize",sum); Document group = new Document(); group.put("$group",totalSize); //{$match:{totalSize:{$gt:200}}} Document gt = new Document(); gt.put("$gt",200); Document mtotalSize = new Document(); mtotalSize.put("totalSize",gt); Document match = new Document(); match.put("$match",mtotalSize); List<Document> list = new ArrayList<>(); list.add(group); list.add(match); AggregateIterable iterable = collection.aggregate(list); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); System.out.println(docu.get("totalSize")); } }
3.5.6聚合操作-$project-聚合投影约束
需求:查询 dev 集合,将数组中的内容拆分显示,并只显示 title 键与 tags 键的值。
Mongo Shell:
db.dev.aggregate([{$unwind:"$tags"},{$project:{_id:0,tags:"$tags",title:"$title"}}])
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 需求:查询 dev 集合,将数组中的内容拆分显示,并只显示 title 键与 tags 键的值。 Mongo Shell: db.dev.aggregate([{$unwind:"$tags"},{$project:{_id:0,tags :"$tags",title:"$title"}}]) */ public void selectDocumentProject(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","dev"); Document unwind = new Document(); unwind.put("$unwind","$tags"); Document pro = new Document(); pro.put("_id",0); pro.put("tags","$tags"); pro.put("title","$title"); Document project = new Document(); project.put("$project",pro); List<Document> list = new ArrayList<>(); list.add(unwind); list.add(project); AggregateIterable iterable = collection.aggregate(list); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ System.out.println(cursor.next()); } }
3.5.7聚合操作-$project-字符串处理
需求:查询 dev 集合,将数组中的内容拆分显示。将 title 字段和 tags 字段的值拼接为
一个完整字符串并在 Title_Tags 字段中显示。
Mongo Shell:
db.dev.aggregate([{$unwind:"$tags"},{$project:{_id:0,Title_Tags:{$concat:["$title","-","$tags"]}}}])
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 需求:查询 dev 集合,将数组中的内容拆分显示。将 title 字段和 tags 字段的值拼接为一个完整字符串并在 Title_Tags 字段中显示。 Mongo Shell: db.dev.aggregate([{$unwind:"$tags"},{$project:{_id:0,Titl e_Tags:{$concat:["$title","-","$tags"]}}}]) */ public void selectDocumentProjectConcat(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","dev"); Document unwind = new Document(); unwind.put("$unwind","$tags"); Document concat = new Document(); concat.put("$concat", Arrays.asList(new String[]{"$title","-","$tags"})); Document title = new Document(); title.put("_id",0); title.put("Title_Tags",concat); Document project = new Document(); project.put("$project",title); List<Document> list = new ArrayList<>(); list.add(unwind); list.add(project); AggregateIterable iterable = collection.aggregate(list); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ System.out.println(cursor.next()); } }
3.5.8聚合操作-$project 算术运算
需求:查询 dev 集合中数据,显示 title 和 size 字段,为 size 字段数据做加 1 操作,显
示字段命名为 New_Size。排除那些没有 size 键的文档。
Mongo Shell:
db.dev.aggregate([{$match:{size:{$ne:null}}},{$project:{_id:0,title:1,New_Size:{$add:["$size",1]}}}])
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 需求:查询 dev 集合中数据,显示 title 和 size 字段,为 size 字段数 据做加 1 操作,显示字段命名为 New_Size。排除那些没有 size 键的文档。 Mongo Shell: db.dev.aggregate([{$match:{size:{$ne:null}}},{$project:{_ id:0,title:1,New_Size:{$add:["$size",1]}}}]) */ public void selectDocumentProjectAdd(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","dev"); Document ne = new Document(); ne.put("$ne",null); Document size = new Document(); size.put("size",ne); Document match = new Document(); match.put("$match",size); //{$project:{_id:0,title:1,New_Size:{$add:["$size",1]}}} Document add = new Document(); add.put("$add",Arrays.asList(new Object[]{"$size",1})); Document new_Size = new Document(); new_Size.put("_id",0); new_Size.put("title",1); new_Size.put("New_Size",add); Document project = new Document(); project.put("$project",new_Size); List<Document> list = new ArrayList<>(); list.add(match); list.add(project); AggregateIterable iterable = collection.aggregate(list); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ System.out.println(cursor.next()); } }
3.5.9聚合操作-$project 日期处理
需求:查询 devtest 集合查询那些有生日的用户,并按照 YYYY 年 mm 月 dd 日
HH:MM:SS 格式显示日期。
Mongo Shell:
db.devtest.aggregate([{$match:{userbirth:{$ne:null}}},{$project:{ 自定义日期格
式:{$dateToString:{format:"%Y 年%m 月%d 日 %H:%M:%S",date:"$userbirth"}}}}])
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 需求:查询 devtest 集合查询那些有生日的用户,并按照 YYYY 年 mm 月 dd 日 HH:MM:SS 格式显示日期。 * 注意:如果直接在 MongoDB 中做日期的格式化处理,那么是按照表示 UTC 时间来处理的,会少 8 个小时。建议在程序中 * 通过 java.util.Date 来做日期的转换。 Mongo Shell: db.devtest.aggregate([{$match:{userbirth:{$ne:null}}},{$p roject:{自定义日期格式:{$dateToString:{format:"%Y 年%m 月%d 日 %H:%M:%S",date:"$userbirth"}}}}]) */ public void selectDocumentProjectDate(){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","devtest"); Document ne = new Document(); ne.put("$ne",null); Document birth = new Document(); birth.put("userbirth",ne); Document match = new Document(); match.put("$match",birth); //{$project:{自定义日期格式:{$dateToString:{format:"%Y 年%m 月%d 日 %H:%M:%S",date:"$userbirth"}}}} Document format = new Document(); format.put("format","%Y 年%m 月%d 日 %H:%M:%S"); format.put("date","$userbirth"); Document dateToString = new Document(); dateToString.put("$dateToString",format); Document custoDate = new Document(); custoDate.put("自定义日期格式",dateToString); Document project = new Document(); project.put("$project",custoDate); List<Document> list = new ArrayList<>(); list.add(match); list.add(project); AggregateIterable iterable = collection.aggregate(list); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ System.out.println(cursor.next()); } }
3.6分页查询
3.6.1使用 skip 与 limit 方法分页
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 通过 skip 与 limit 方法实现分页 */ public void selectDocumentByPageUseSkipAndLimit(int pageIndex){ int page = (pageIndex-1)*2; MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","dev"); Document condition = new Document("size",new Document("$ne",null)); long countNum = collection.countDocuments(condition); System.out.println(countNum); FindIterable iterable = collection.find(condition).skip(page).limit(2); MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); System.out.println(docu); } }
3.6.2优化分页查询
使用条件判断替换 skip 方法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 通过条件判断实现分页 */ public void selectDocumentByPageUseCondition(int pageIndex,int pageSize,String lastId){ MongoCollection collection = MongoDBAuthPoolUtil.getCollection("develop","dev"); Document condition = new Document("size",new Document("$ne",null)); long countNum = collection.countDocuments(condition); System.out.println(countNum); FindIterable iterable = null; if(pageIndex == 1){ iterable = collection.find(condition).limit(pageSize); }else{ if(lastId != null){ condition.append("_id",new Document("$gt",new ObjectId(lastId))); iterable = collection.find(condition).limit(pageSize); } } MongoCursor<Document> cursor = iterable.iterator(); while(cursor.hasNext()){ Document docu = cursor.next(); System.out.println(docu); } }