讲师简介

smart哥,互联网悍将,历经从传统软件公司到大型互联网公司的洗礼,入行即在中兴通讯等大型通信公司担任项目leader,后随着互联网的崛起,先后在美团支付等大型互联网公司担任架构师,公派旅美期间曾与并发包大神Doug Lea探讨java多线程等最底层的核心技术。对互联网架构底层技术有相当的研究和独特的见解,在多个领域有着丰富的实战经验。

一、MongoDB历史

MongoDB最初于2007年开发,当时公司正在建立一个类似于窗口天蓝(window azure)的服务平台。

“Window azure是由Microsoft创建的云计算平台和基础设施,通过全球网络构建,部署和管理应用程序和服务。”

MongoDB由位于纽约的一个名为10gen的组织开发,现在被称为MongoDB Inc.,它最初被开发为PAAS(平台即服务), 2009年晚些时候,它被作为一个由MongoDB公司维护和支持的开源数据库服务器在市场上引入。

MongoDB的第一个真正产品是从2010年3月发布的MongoDB 1.4版本开始的,现在的最新版本:MongoDB4.4.1

首先应该知道什么是面向文档的数据库?

oracle,db2,mysql,sqlserver----关系型数据库 E.F CODD

mongoDB。json,bson

1、面向文档的数据库示例

MongoDB是面向文档的数据库,这是MongoDB的一个主要功能,它提供面向文档的存储。

MongoDB将数据存储为文档,因此被称为面向文档的数据库。

FirstName = "maxuan",
Address = "nanJing city",
Spouse = [{Name: "MaXuan"},{Name:"MaXuan1"}].
FirstName ="maxuan1",  
Address = "shanghai city"

有两个不同的文件(用“.”分隔开),以这种方式存储数据称为面向文档的数据库。

Mongodb属于一类名为面向文档数据库(Document Oriented Databases),它属于一个叫作“NoSQL数据库”的数据库类别称。

mongodb,redis都属于nosql,

no sql=not only sql

​ 后端 json list 表-》实体类(Person)

前端-》controller-》service-》dao-》mybatis-》mysql

二、MongoDB特点

下面列出的是MongoDB的一些重要功能特性:

1.支持特别查询

  • 在MongoDB中,可以通过字段,范围查询进行搜索,并且还支持正则表达式搜索。

2.索引

  • 可以索引文档中的任何字段。

3.复制

  • MongoDB支持主从复制,主机可以执行读写操作,从机从主机复制数据,只能用于读取或备份(不写入)

4.复制数据

  • MongoDB可以在多台服务器上运行, 复制数据以保持系统正常运行,并在硬件故障的情况下保持其运行状态。

5.负载均衡

  • 由于数据放在碎片中,因此具有自动负载平衡配置。

6.支持映射缩减和聚合工具

7.使用JavaScript而不是Procedure

8.它是一个用C++编写的无模式数据库

9.提供高性能

10.轻松存储任何大小的文件,而不会使您的堆栈复杂化

11.在故障的情况下易于管理

12.它还支持:

  • 具有动态模式的JSON数据模型
  • 自动分片用于水平可扩展性
  • 内置复制高可用性

现在,许多公司使用 MongoDB 来创建新类型的应用程序,以提高性能和可用性。

mmap(零拷贝),tomcat sendfile

场景:会计,银行,支付等数据建议还是放到关系型数据库里。

三、MongoDB数据库的优点

到目前为止,MongoDB是一个新的和普遍使用的数据库, 它是一个基于文档的非关系数据库提供程序。

虽然它比传统的数据库快100倍,但早期说它将广泛地取代传统的RDBMS, 但是,不可否认的是:在性能和可扩展性方面 MongoDB 有着明显的优势。

关系数据库具有典型的架构设计,可以显示表的数量以及这些表之间的关系,而在MongoDB中则没有关系的概念。

1、MongoDB优点

  • MongoDB 的架构较少,它是一个文档数据库,它的一个集合持有不同的文档。
  • 从一个到另一个的文档的数量,内容和大小可能有差异。
  • MongoDB 中单个对象的结构很清淅。
  • MongoDB 中没有复杂的连接。
  • MongoDB 提供深度查询的功能,因为它支持对文档的强大的动态查询。
  • MongoDB 很容易扩展。
  • 它使用内部存储器来存储工作集,这是其快速访问的原因。

2、MongoDB的独特功能

  • 使用方便
  • 重量轻/轻量级
  • 比RDBMS快得多(用了mmap)

3、应该使用MongoDB在哪些场景

  • 大而复杂的数据
  • 移动和社会基础设施数据
  • 内容管理和交付
  • 用户数据管理
  • 数据中心

4、MongoDB和RDBMS的性能分析

  • 在关系数据库(RDBMS)中,表用作存储元素,而在 MongoDB 中使用的是集合。
  • 在RDBMS中有多个模式,在每个模式中,可创建用于存储数据的表,而 MongoDB 是面向文档的数据库,数据是以类似JSON格式的BSON格式编写的存储的。
  • MongoDB几乎比传统数据库系统快100倍。

四、MongoDB安装配置(Windows)

要在Windows上安装 MongoDB,首先打开: https://www.mongodb.com/try/download/community 下载最新版本的MongoDB,确保根据您的Windows版本获得正确版本的MongoDB,要获取 Windows 版本,请打开命令提示符并执行以下命令。

C:\Users\ling> wmic os get osarchitecture
OSArchitecture
64 位

如上所示,这里 Windows 版本是 64位的操作系统,所以下载对应的 MongoDB-for-Windows 64位版本,如下图所示 -

image-20200922131752832

1、前提条件

MongoDB社区版需要Windows Server 2008 R2,Windows Vista或更高版本(注:本教程将演示在Windows8 64位系统上安装MongoDB),本课程使用zip解压版mongodb-windows-x86_64-4.4.1.zip。

2、MongoDB安装

在下载目录D:\360Downloads中,找到mongodb-windows-x86_64-4.4.1.zip,解压后

image-20200922163933252

新建data和logs目录后(这里需要手动去创建这俩目录),打开cmd(管理员),执行

D:\360Downloads\mongodb\bin>mongod.exe --install --dbpath D:\360Downloads\mongod
b\data --logpath D:\360Downloads\mongodb\logs\mongodb.log

报错“无法定位程序输入点BCryHash于动态链接库”。

该错误实际是我本机是win8系统,不支持最新版本4.4.1,于是降低一个版本,选择4.2.9安装。

image-20200922164436454

下载 .msi 文件,下载后双击该文件,按操作提示安装即可。

image-20200922164725351

勾选接受协议,点击【next】

image-20200922165231278

安装过程中,你可以通过点击 "Custom(自定义)" 按钮来设置你的安装目录。

image-20200922165349135

选择完点击【next】。

这里选择安装目录

image-20200922165635109

我选择安装在d盘下

image-20200922165656697

点击【ok】,然后【next】

这里采用默认设置,安装为windows服务,下面两个目录他给我指定了data和log文件夹分别用来放数据和日志。

image-20200922165758487

点击【next】进入下一步。

下一步安装 "install mongoDB compass" 不勾选(当然你也可以选择安装它,可能需要更久的安装时间),MongoDB Compass 是一个图形界面管理工具,我们可以在后面自己到官网下载安装,下载地址:https://www.mongodb.com/download-center/compass

image-20200922170037372

点击【next】,然后点击【install】开始安装。

安装完之后,我们打开【运行】,输入“services.msc” 回车,打开windows服务,然后发现Mongodb已经安装为windows服务了,如下图:

image-20200922170744063

我们可以通过管理员命令行执行 net stop MongoDBnet start MongoDB启动和停止MongoDB服务,如下图:

image-20200922171104919

如果想卸载这个服务则执行:mongod.exe --remove即可

3、启动MongoDB

要启动 MongoDB,请运行 mongod.exe 。 例如,从命令提示符:

D:\Program Files\MongoDB\Server\4.2\bin\mongod.exe --dbpath D:\MongoDB\Server\4.2\data

注意:如果不使用 --dbpath 指定数据存储的目录, 将启动不成功。

这里最好配置下环境变量,这样操作更方便。

默认端口号是27017,当然我们可以自己指定端口号,用--port参数指定,端口号最大不要超过65535。

在执行上面命令启动后,应该会看到类似下面的输出结果:

d:\MongoDB\Server\4.2\bin>mongod.exe --dbpath D:\MongoDB\Server\4.2\data
2020-09-22T17:30:53.388+0800 I  CONTROL  [main] Automatically disabling TLS 1.0,
 to force-enable TLS 1.0 specify --sslDisabledProtocols 'none'
2020-09-22T17:30:53.397+0800 W  ASIO     [main] No TransportLayer configured dur
ing NetworkInterface startup
2020-09-22T17:30:53.399+0800 I  CONTROL  [initandlisten] MongoDB starting : pid=
25912 port=27017 dbpath=D:\MongoDB\Server\4.2\data 64-bit host=mydell
2020-09-22T17:30:53.399+0800 I  CONTROL  [initandlisten] targetMinOS: Windows 7/
Windows Server 2008 R2
2020-09-22T17:30:53.399+0800 I  CONTROL  [initandlisten] db version v4.2.9
2020-09-22T17:30:53.400+0800 I  CONTROL  [initandlisten] git version: 0640211411
4ffc5146fd4b55402c96f1dc9ec4b5
2020-09-22T17:30:53.400+0800 I  CONTROL  [initandlisten] allocator: tcmalloc
2020-09-22T17:30:53.400+0800 I  CONTROL  [initandlisten] modules: none
2020-09-22T17:30:53.401+0800 I  CONTROL  [initandlisten] build environment:
2020-09-22T17:30:53.401+0800 I  CONTROL  [initandlisten]     distmod: 2012plus
2020-09-22T17:30:53.402+0800 I  CONTROL  [initandlisten]     distarch: x86_64
2020-09-22T17:30:53.402+0800 I  CONTROL  [initandlisten]     target_arch: x86_64

2020-09-22T17:30:53.402+0800 I  CONTROL  [initandlisten] options: { storage: { d
bPath: "D:\MongoDB\Server\4.2\data" } }
2020-09-22T17:30:53.405+0800 I  STORAGE  [initandlisten] Detected data files in
D:\MongoDB\Server\4.2\data created by the 'wiredTiger' storage engine, so settin
g the active storage engine to 'wiredTiger'.
2020-09-22T17:30:53.405+0800 I  STORAGE  [initandlisten] wiredtiger_open config:
 create,cache_size=7637M,cache_overflow=(file_max=0M),session_max=33000,eviction
=(threads_min=4,threads_max=4),config_base=false,statistics=(fast),log=(enabled=
true,archive=true,path=journal,compressor=snappy),file_manager=(close_idle_time=
100000,close_scan_interval=10,close_handle_minimum=250),statistics_log=(wait=0),
verbose=[recovery_progress,checkpoint_progress],
2020-09-22T17:30:53.485+0800 I  STORAGE  [initandlisten] WiredTiger message [160
0767053:484129][25912:140716452810880], txn-recover: Recovering log 2 through 3
2020-09-22T17:30:53.571+0800 I  STORAGE  [initandlisten] WiredTiger message [160
0767053:571179][25912:140716452810880], txn-recover: Recovering log 3 through 3
2020-09-22T17:30:53.671+0800 I  STORAGE  [initandlisten] WiredTiger message [160
0767053:671255][25912:140716452810880], txn-recover: Main recovery loop: startin
g at 2/10496 to 3/256
2020-09-22T17:30:53.848+0800 I  STORAGE  [initandlisten] WiredTiger message [160
0767053:847375][25912:140716452810880], txn-recover: Recovering log 2 through 3
2020-09-22T17:30:53.966+0800 I  STORAGE  [initandlisten] WiredTiger message [160
0767053:966462][25912:140716452810880], txn-recover: Recovering log 3 through 3
2020-09-22T17:30:54.052+0800 I  STORAGE  [initandlisten] WiredTiger message [160
0767054:51523][25912:140716452810880], txn-recover: Set global recovery timestam
p: (0, 0)
2020-09-22T17:30:54.136+0800 I  RECOVERY [initandlisten] WiredTiger recoveryTime
stamp. Ts: Timestamp(0, 0)
2020-09-22T17:30:54.145+0800 I  STORAGE  [initandlisten] Timestamp monitor start
ing
2020-09-22T17:30:54.153+0800 I  CONTROL  [initandlisten]
2020-09-22T17:30:54.153+0800 I  CONTROL  [initandlisten] ** WARNING: Access cont
rol is not enabled for the database.
2020-09-22T17:30:54.153+0800 I  CONTROL  [initandlisten] **          Read and wr
ite access to data and configuration is unrestricted.
2020-09-22T17:30:54.154+0800 I  CONTROL  [initandlisten]
2020-09-22T17:30:54.154+0800 I  CONTROL  [initandlisten] ** WARNING: This server
 is bound to localhost.
2020-09-22T17:30:54.155+0800 I  CONTROL  [initandlisten] **          Remote syst
ems will be unable to connect to this server.
2020-09-22T17:30:54.155+0800 I  CONTROL  [initandlisten] **          Start the s
erver with --bind_ip <address> to specify which IP
2020-09-22T17:30:54.155+0800 I  CONTROL  [initandlisten] **          addresses i
t should serve responses from, or with --bind_ip_all to
2020-09-22T17:30:54.156+0800 I  CONTROL  [initandlisten] **          bind to all
 interfaces. If this behavior is desired, start the
2020-09-22T17:30:54.156+0800 I  CONTROL  [initandlisten] **          server with
 --bind_ip 127.0.0.1 to disable this warning.
2020-09-22T17:30:54.157+0800 I  CONTROL  [initandlisten]
2020-09-22T17:30:54.161+0800 I  SHARDING [initandlisten] Marking collection loca
l.system.replset as collection version: <unsharded>
2020-09-22T17:30:54.166+0800 I  STORAGE  [initandlisten] Flow Control is enabled
 on this deployment.
2020-09-22T17:30:54.166+0800 I  SHARDING [initandlisten] Marking collection admi
n.system.roles as collection version: <unsharded>
2020-09-22T17:30:54.166+0800 I  SHARDING [initandlisten] Marking collection admi
n.system.version as collection version: <unsharded>
2020-09-22T17:30:54.170+0800 I  SHARDING [initandlisten] Marking collection loca
l.startup_log as collection version: <unsharded>
2020-09-22T17:30:54.596+0800 I  FTDC     [initandlisten] Initializing full-time
diagnostic data capture with directory 'D:/MongoDB/Server/4.2/data/diagnostic.da
ta'
2020-09-22T17:30:54.600+0800 I  SHARDING [LogicalSessionCacheRefresh] Marking co
llection config.system.sessions as collection version: <unsharded>
2020-09-22T17:30:54.601+0800 I  SHARDING [LogicalSessionCacheReap] Marking colle
ction config.transactions as collection version: <unsharded>
2020-09-22T17:30:54.601+0800 I  NETWORK  [listener] Listening on 127.0.0.1
2020-09-22T17:30:54.601+0800 I  NETWORK  [listener] waiting for connections on p
ort 27017
2020-09-22T17:30:55.002+0800 I  SHARDING [ftdc] Marking collection local.oplog.r
s as collection version: <unsharded>
2020-09-22T17:31:19.971+0800 I  NETWORK  [listener] connection accepted from 127
.0.0.1:26315 #1 (1 connection now open)
2020-09-22T17:31:19.976+0800 I  NETWORK  [conn1] received client metadata from 1
27.0.0.1:26315 conn1: { application: { name: "MongoDB Shell" }, driver: { name:
"MongoDB Internal Client", version: "4.2.9" }, os: { type: "Windows", name: "Mic
rosoft Windows 8.1", architecture: "x86_64", version: "6.3 (build 9600)" } }
2020-09-22T17:31:27.196+0800 I  NETWORK  [conn1] end connection 127.0.0.1:26315
(0 connections now open)

打开 MongoDB 客户端测试使用

d:\MongoDB\Server\4.2\bin>mongo.exe
MongoDB shell version v4.2.9
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName
=mongodb
Implicit session: session { "id" : UUID("e2a59c72-86f1-4799-a6c3-b171b2f788a0")
}
MongoDB server version: 4.2.9
Server has startup warnings:
2020-09-22T17:30:54.153+0800 I  CONTROL  [initandlisten]
2020-09-22T17:30:54.153+0800 I  CONTROL  [initandlisten] ** WARNING: Access cont
rol is not enabled for the database.
2020-09-22T17:30:54.153+0800 I  CONTROL  [initandlisten] **          Read and wr
ite access to data and configuration is unrestricted.
2020-09-22T17:30:54.154+0800 I  CONTROL  [initandlisten]
2020-09-22T17:30:54.154+0800 I  CONTROL  [initandlisten] ** WARNING: This server
 is bound to localhost.
2020-09-22T17:30:54.155+0800 I  CONTROL  [initandlisten] **          Remote syst
ems will be unable to connect to this server.
2020-09-22T17:30:54.155+0800 I  CONTROL  [initandlisten] **          Start the s
erver with --bind_ip <address> to specify which IP
2020-09-22T17:30:54.155+0800 I  CONTROL  [initandlisten] **          addresses i
t should serve responses from, or with --bind_ip_all to
2020-09-22T17:30:54.156+0800 I  CONTROL  [initandlisten] **          bind to all
 interfaces. If this behavior is desired, start the
2020-09-22T17:30:54.156+0800 I  CONTROL  [initandlisten] **          server with
 --bind_ip 127.0.0.1 to disable this warning.
2020-09-22T17:30:54.157+0800 I  CONTROL  [initandlisten]
---
Enable MongoDB's free cloud-based monitoring service, which will then receive an
d display
metrics about your deployment (disk utilization, CPU, operation statistics, etc)
.

The monitoring data will be available on a MongoDB website with a unique URL acc
essible to you
and anyone you share the URL with. MongoDB may use this information to make prod
uct
improvements and to suggest MongoDB products and deployment options to you.

To enable free monitoring, run the following command: db.enableFreeMonitoring()
To permanently disable this reminder, run the following command: db.disableFreeM
onitoring()
---
##执行show databases查看默认的库
> show databases
admin   0.000GB
config  0.000GB
local   0.000GB

MongoDB帮助

要获取命令列表,请在MongoDB客户端中键入:db.help()。 这将列出一个命令列表,如下面的屏幕截图所示 -

> db.help()
DB methods:
        db.adminCommand(nameOrDocument) - switches to 'admin' db, and runs command [ just calls db.runCommand(...) ]
        db.auth(username, password)
        db.cloneDatabase(fromhost)
        db.commandHelp(name) returns the help for the command
        db.copyDatabase(fromdb, todb, fromhost)
        db.createCollection(name, { size : ..., capped : ..., max : ... } )
        db.createView(name, viewOn, [ { $operator: {...}}, ... ], { viewOptions } )
        db.createUser(userDocument)
        db.currentOp() displays currently executing operations in the db
        db.dropDatabase()
        db.eval() - deprecated
        db.fsyncLock() flush data to disk and lock server for backups
        db.fsyncUnlock() unlocks server following a db.fsyncLock()
        db.getCollection(cname) same as db['cname'] or db.cname
        db.getCollectionInfos([filter]) - returns a list that contains the names and options of the db's collections
        db.getCollectionNames()
        db.getLastError() - just returns the err msg string
        db.getLastErrorObj() - return full status object
        db.getLogComponents()
        db.getMongo() get the server connection object
        db.getMongo().setSlaveOk() allow queries on a replication slave server
        db.getName()
        db.getPrevError()
        db.getProfilingLevel() - deprecated
        db.getProfilingStatus() - returns if profiling is on and slow threshold
        db.getReplicationInfo()
        db.getSiblingDB(name) get the db at the same server as this one
        db.getWriteConcern() - returns the write concern used for any operations on this db, inherited from server object if set
        db.hostInfo() get details about the server's host
        db.isMaster() check replica primary status
        db.killOp(opid) kills the current operation in the db
        db.listCommands() lists all the db commands
        db.loadServerScripts() loads all the scripts in db.system.js
        db.logout()
        db.printCollectionStats()
        db.printReplicationInfo()
        db.printShardingStatus()
        db.printSlaveReplicationInfo()
        db.dropUser(username)
        db.repairDatabase()
        db.resetError()
        db.runCommand(cmdObj) run a database command.  if cmdObj is a string, turns it into { cmdObj : 1 }
        db.serverStatus()
        db.setLogLevel(level,<component>)
        db.setProfilingLevel(level,<slowms>) 0=off 1=slow 2=all
        db.setWriteConcern( <write concern doc> ) - sets the write concern for writes to the db
        db.unsetWriteConcern( <write concern doc> ) - unsets the write concern for writes to the db
        db.setVerboseShell(flag) display extra information in shell output
        db.shutdownServer()
        db.stats()
        db.version() current version of the server
>

MongoDB统计

要获取有关MongoDB服务器的统计信息,请在 MongoDB 客户端中键入命令:db.stats()。 这个命令将显示数据库名称,数据库中的集合和文档数量。命令的输出如下面的截图所示 -

> db.stats()
{
        "db" : "test",
        "collections" : 0,
        "views" : 0,
        "objects" : 0,
        "avgObjSize" : 0,
        "dataSize" : 0,
        "storageSize" : 0,
        "numExtents" : 0,
        "indexes" : 0,
        "indexSize" : 0,
        "scaleFactor" : 1,
        "fileSize" : 0,
        "fsUsedSize" : 0,
        "fsTotalSize" : 0,
        "ok" : 1
}
>

五、MongoDB安装配置(RedHat/CentOS)

1、下载

https://www.mongodb.com/try/download/community

选择最新4.4.1版本(服务器为centos7),选择tar压缩包,具体如下:

image-20200923200927467

2、上传解压

将下载完的mongodb-linux-x86_64-rhel70-4.4.1.tgz包上传至/usr/local下

image-20200924093905634

解压安装

 tar -zxvf mongodb-linux-x86_64-rhel70-4.4.1.tgz 
 mv mongodb-linux-x86_64-rhel70-4.4.1 /usr/local/mongodb

image-20200924094138834

3、配置conf与目录

1)、进入mongodb,创建data目录和logs目录,并创建mongodb.log文件

mkdir -p ./data
mkdir -p ./logs
touch ./logs/mongodb.log

image-20200924094627834

2)、创建mongodb.conf

vi mongodb.conf

#端口号
port=27017
#db目录
dbpath=/usr/local/mongodb/data
#日志目录
logpath=/usr/local/mongodb/logs/mongodb.log
#后台
fork=true
#日志输出
logappend=true
#允许远程IP连接
bind_ip=0.0.0.0

4、启动测试

image-20200924095811857

客户端连接成功

image-20200924095953548

执行 show dbs

show dbs

image-20200924100049821

成功!!

六、MongoDB数据建模

MongoDB中的数据具有灵活的模式。文档在同一集合,但它们不需要具有相同的字段或结构集合,集合文档中的公共字段可以包含不同类型的数据。

MongoDB中的数据具有灵活的模式。与SQL数据库不同,SQL数据库必须在插入数据之前确定和声明表的模式,MongoDB的集合不会强制执行文档结构。这种灵活性有助于将文档映射到实体或对象。 每个文档可以匹配表示实体的数据字段,即使数据具有实质性的变化。然而,集合中的文档具有类似的结构。

数据建模中的关键挑战是平衡应用程序的需求,数据库引擎的性能特征和数据检索模式。 在设计数据模型时,请始终考虑数据的应用程序使用情况(即数据的查询,更新和处理)以及数据本身的固有结构。

在MongoDB中设计架构时有一些考虑:

  • 根据用户要求设计架构。
  • 将对象合并到一个文档中,否则分开它们(但确保不需要连接)。
  • 复制数据(但有限制),因为与计算时间相比,磁盘空间便宜。
  • 在写入时加入,而不是读取时加入。
  • 为最常用的用例优化架构。
  • 在模式中执行复杂聚合。

1、实例

假设客户需要他的博客/网站的数据库设计,并查看RDBMS和MongoDB架构设计之间的区别。网站有以下要求。

  • 每个帖子都有唯一的标题,描述和网址。
  • 每个帖子都可以有一个或多个标签。
  • 每个帖子都有其发布者的名称和总人数。
  • 每个帖子都有用户给出的评论以及他们的姓名,消息,数据时间和喜好。
  • 每个帖子可以有零个或多个评论。

在RDBMS架构中,上述要求的设计将具有最少的三个表。表与表之间的关系如下 -

img

select post. ,comments. ,tag_list. * from post, comments ,tag_list

where post.id=comments.post_id and post.id=tag_list.post_id

而在MongoDB模式中,设计将有一个集合post,其结构以下 -

{
   _id: POST_ID
   title: TITLE_OF_POST, 
   description: POST_DESCRIPTION,
   by: POST_BY,
   url: URL_OF_POST,
   tags: [TAG1, TAG2, TAG3],
   likes: TOTAL_LIKES, 
   comments: [    
      {
         user:'COMMENT_BY',
         message: TEXT,
         dateCreated: DATE_TIME,
         like: LIKES 
      },
      {
         user:'COMMENT_BY',
         message: TEXT,
         dateCreated: DATE_TIME,
         like: LIKES
      }
   ]
}

通过上面的示例说明可以知道,在显示数据时,在RDBMS中需要连接三个表,而在MongoDB中,数据将仅显示在一个集合中。

2、基本概念

  • 文档(document)
    • 类似于js中的对象,在MongoDB中每一条数据就是一个文档。

    文档=关系数据库中的表记录

  • 集合(collection)
    • 集合就是一组文档,也就是集合是用来存放文档的
    • 集合中存储的文档可以是各种各样的,没有格式要求。

    集合=关系数据库中

  • 多个文档组成集合,多个集合组成数据库。

​ 库=关系数据库里的库

库》表》记录

库》集合》文档

七、MongoDB创建数据库

本章将介绍如何在 MongoDB 中创建数据库。

1、use 命令

MongoDB使用 use DATABASE_NAME 命令来创建数据库。

注意:如果指定的数据库DATABASE_NAME不存在,则该命令将创建一个新的数据库,否则返回现有的数据库。

语法

use DATABASE 语句的基本语法如下 -

use DATABASE_NAME

2、示例

如果要创建一个名称为<newdb>的数据库,那么使用 use DATABASE 语句将如下所示:

> use newdb
switched to db newdb

要检查当前选择的数据库,请使用 db 命令 -

>db
newdb

如果要检查数据库列表,请使用命令:show dbs

> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB

创建的数据库(newdb)不在列表中,要显示数据库,需要至少插入一个文档,空的数据库是不显示出来的。

>db.items.insert({name:"maxuan course"})
>show dbs
local     0.00005GB
test      0.00002GB
newdb      0.00002GB

在 MongoDB 中默认数据库是:test。 如果您还没有创建过任何数据库,则集合/文档将存储在test数据库中。

八、MongoDB删除数据库

本章将介绍如何在 MongoDB 中删除数据库。

1、db.dropDatabase() 方法

MongoDB中的 db.dropDatabase()命令用于删除现有的数据库。

db.dropDatabase()

这将删除当前所选数据库, 如果没有选择任何数据库,那么它将删除默认的’test‘数据库。

2、示例

首先,使用命令show dbs检查可用数据库的列表。

>show dbs
local      0.00025GB
newdb       0.0002GB
test       0.00012GB
>

如果要删除新数据库<newdb>,那么dropDatabase()命令将如下所示:

>use newdb
switched to db newdb
>db.dropDatabase()
>{ "dropped" : "newdb", "ok" : 1 }
>

现在检查数据库列表,如下 -

>show dbs
local      0.00025GB
test       0.0002GB
>

九、MongoDB创建集合

在本章中,我们将学习如何在 MongoDB 中创建一个集合。

1、createCollection()方法

MongoDB 的 db.createCollection(name,options) 方法用于在MongoDB 中创建集合。

语法

createCollection()命令的基本语法如下:

db.createCollection(name, options)

在命令中,name 是要创建的集合的名称。 options是一个文档,用于指定集合的配置。

参数 类型 描述
name String 要创建的集合的名称
options Document (可选)指定有关内存大小和索引的选项

options参数是可选的,因此只需要指定集合的名称。 以下是可以使用的选项列表:

字段 类型 描述
capped Boolean (可选)如果为true,则启用封闭的集合。上限集合是固定大小的集合,它在达到其最大大小时自动覆盖其最旧的条目。 如果指定true,则还需要指定size参数。
size 数字 (可选)指定上限集合的最大大小(以字节为单位)。 如果cappedtrue,那么还需要指定此字段的值。
max 数字 (可选)指定上限集合中允许的最大文档数。

在插入文档时,MongoDB首先检查上限集合capped字段的大小,然后检查max字段。

size 是整个集合空间大小,单位为【KB】

max 是集合文档个数上线,单位是【个】

如果空间大小到达上限,则插入下一个文档时,会覆盖第一个文档;如果文档个数到达上限,同样插入下一个文档时,会覆盖第一个文档。两个参数上限判断取的是【与】的逻辑。

2、例子

没有使用选项的createCollection()方法的基本语法如下 -

>use test
switched to db test
>db.createCollection("user")
{ "ok" : 1 }
>

可以使用命令show collections检查创建的集合。

>show collections
user

以下示例显示了createCollection()方法的语法,其中几个重要选项 -

> db.createCollection("user1", {capped : true, size : 6291456, max : 10000 })
{ "ok" : 1 }
>

在 MongoDB 中,不需要创建集合,当插入一些文档时,MongoDB 会自动创建集合。

>db.newcollection.insert({"name" : "maxuan course"})
>show collections
user
user1
user2
>

十、MongoDB删除集合

在本章节中,我们将演示如何删除 MongoDB 中的集合。

1、drop()方法

MongoDB 的 db.collection.drop() 用于从数据库中删除集合。

语法

drop()命令的基本语法如下 -

db.COLLECTION_NAME.drop()

2、示例

首先,检查数据库 test 中可用的集合。

>use test
switched to db test
> show collections
user
user1
user2
>

现在删除名称为 user 的集合。

>db.user.drop()
true
>

再次检查当前数据库的集合列表,如下 -

> show collections
user1
user2
>

如果选定的集合成功删除,drop()方法将返回true,否则返回false

十一、MongoDB数据类型

MongoDB支持许多数据类型,如下:

  • 字符串 - 这是用于存储数据的最常用的数据类型。MongoDB中的字符串必须为UTF-8
  • 整型 - 此类型用于存储数值。 整数可以是32位或64位,具体取决于服务器。
  • 布尔类型 - 此类型用于存储布尔值(true / false)值。
  • 双精度浮点数 - 此类型用于存储浮点值。
  • 最小/最大键 - 此类型用于将值与最小和最大BSON元素进行比较。
  • 数组 - 此类型用于将数组或列表或多个值存储到一个键中。
  • 时间戳 - ctimestamp,当文档被修改或添加时,可以方便地进行录制。
  • 对象 - 此数据类型用于嵌入式文档。
  • Null - 此类型用于存储Null值。
  • 符号 - 该数据类型与字符串相同; 但是,通常保留用于使用特定符号类型的语言。
  • 日期 - 此数据类型用于以UNIX时间格式存储当前日期或时间。您可以通过创建日期对象并将日,月,年的日期进行指定自己需要的日期时间。
  • 对象ID - 此数据类型用于存储文档的ID。
  • 二进制数据 - 此数据类型用于存储二进制数据。
  • 代码 - 此数据类型用于将JavaScript代码存储到文档中。
  • 正则表达式 - 此数据类型用于存储正则表达式。

十二、MongoDB插入文档

在本章中,我们将学习如何在MongoDB集合中插入文档。

1、insert()方法

要将数据插入到 MongoDB 集合中,需要使用 MongoDB 的 insert()save()方法。

语法

insert()命令的基本语法如下:

>db.COLLECTION_NAME.insert(document)

示例

>db.post.insert({
   _id: 100,
   title: 'MongoDB Overview', 
   description: 'MongoDB is no sql database',
   by: 'maxuan course',
   url: 'http://www.maxuan.com',
   tags: ['mongodb', 'database', 'NoSQL'],
   likes: 100,
})

这里post是集合的名称,在前一章中所创建的,如果数据库中不存在集合,则MongoDB将创建此集合,然后将文档插入到该集合中。

在插入的文档中,如果不指定_id参数,那么 MongoDB 会为此文档分配一个唯一的ObjectId。

_id为集合中的每个文档唯一的12个字节的十六进制数。 12字节划分如下 -

_id: ObjectId(4 bytes timestamp, 3 bytes machine id, 2 bytes process id, 
   3 bytes incrementer)

要在单个查询中插入多个文档,可以在insert()命令中传递文档数组。如下所示 -

> db.post.insert([
   {
      _id: 101,
      title: 'MongoDB Guide', 
      description: 'MongoDB is no sql database',
      by: 'maxuan course',
      url: 'http://www.maxuan.com',
      tags: ['mongodb', 'database', 'NoSQL'],
      likes: 100
   },

   {
      _id: 102,
      title: 'NoSQL Database', 
      description: "NoSQL database doesn't have tables",
      by: 'maxuan course',
      url: 'http://www.maxuan.com',
      tags: ['mongodb', 'database', 'NoSQL'],
      likes: 210, 
      comments: [
         {
            user:'user1',
            message: 'My first comment',
            dateCreated: new Date(2022,11,10,2,35),
            like: 0 
         }
      ]
   },
   {
      _id: 104,
      title: 'Python Quick Guide', 
      description: "Python Quick start ",
      by: 'maxuan course',
      url: 'http://www.maxuan.com',
      tags: ['Python', 'database', 'NoSQL'],
      likes: 30, 
      comments: [
         {
            user:'user1',
            message: 'My first comment',
            dateCreated: new Date(2018,11,10,2,35),
            like: 590 
         }
      ]
   }
])

要插入文档,也可以使用db.post.save(document), 如果不在文档中指定_id,那么save()方法将与insert()方法一样自动分配ID的值,如果指定_id,则将以save()方法的形式替换包含_id的文档的全部数据。

2、其它插入文档的方法

1)、db.collection.insertOne()方法

db.collection.insertOne()方法将单个文档插入到集合中。以下示例将新文档插入到库存集合中。 如果文档没有指定_id字段,MongoDB会自动将_id字段与ObjectId值添加到新文档。

db.user.insertOne(
   { name: "maxuan", age: 21, tags: ["smart"], addr: { city: "nanjing", street:"xinjiekou"} }
)

db.collection.insertOne()方法返回包含新插入的文档的_id字段值的文档。

执行结果如下 -

> db.user.insertOne(
...    { name: "maxuan", age: 21, tags: ["smart"], addr: { city: "nanjing", street:"xinjiekou"} }
... )
{
        "acknowledged" : true,
        "insertedId" : ObjectId("5f21dced38bd23b28b269b59")
}
>

2)、db.collection.insertMany()方法

db.collection.insertMany()方法将多个文档插入到集合中,可将一系列文档传递给db.collection.insertMany()方法。以下示例将三个新文档插入到库存集合中。如果文档没有指定_id字段,MongoDB会向每个文档添加一个ObjectId值的_id字段。

db.user.insertMany([
   { name: "maxuan1", age: 21, tags: ["smart"], addr: { city: "nanjing", street:"xinjiekou"} },
   { name: "maxuan2", age: 22, tags: ["smart"], addr: { city: "shanghai", street:"nanjinglu"} },
   { name: "maxuan3", age: 23, tags: ["smart"], addr: { city: "suzhou", street:"chengxianjie"} } 
])

insertMany()返回包含新插入的文档_id字段值的文档。执行结果如下:

> db.user.insertMany([
...    { name: "maxuan1", age: 21, tags: ["smart"], addr: { city: "nanjing", street:"xinjiekou"} },
...    { name: "maxuan2", age: 22, tags: ["smart"], addr: { city: "shanghai", street:"nanjinglu"} },
...    { name: "maxuan3", age: 23, tags: ["smart"], addr: { city: "suzhou", street:"chengxianjie"} }
... ])
{
        "acknowledged" : true,
        "insertedIds" : [
                ObjectId("59552c1c46be576f199feb56"),
                ObjectId("59552c1c46be576f199feb57"),
                ObjectId("59552c1c46be576f199feb58")
        ]
}
>

3)、js脚本插入

for(var i=0;i<10;i++){
    db.user1.insert({name:"maxuan"+i,age:i,tags:["smart"+i],addr:{city:"nanjing"},street:"xinjiekou"})
}

3、图像化管理工具

下载地址:https://www.mongodbmanager.com/download

image-20200923110555109

安装步骤见视频

十三、MongoDB查询文档

在本章中,我们将学习如何从MongoDB集合中查询文档。

1、find()方法

要从MongoDB集合查询数据,需要使用MongoDB的find()方法。

语法

find()命令的基本语法如下:

>db.COLLECTION_NAME.find(document)

find()方法将以非结构化的方式显示所有文档。

find,返回集合,可以按照下标获取document

2、pretty()方法

要以格式化的方式显示结果,可以使用pretty()方法。

语法

> db.mycol.find().pretty()

示例

>db.mycol.find().pretty()
{
   "_id": 100,
   "title": "MongoDB Overview", 
   "description": "MongoDB is no sql database",
   "by": "maxuan course",
   "url": "http://www.maxuan.com",
   "tags": ["mongodb", "database", "NoSQL"],
   "likes": "100"
}
>

除了find()方法外,还有一个findOne()方法,它只返回一个文档,即findOne,返回document,可以按照key值获取value

3、MongoDB 与 RDBMS的等效 Where 子句

要在一些条件的基础上查询文档,可以使用以下操作。

操作 语法 示例 RDBMS等效语句
相等 {<key>:<value>} db.mycol.find({"by":"maxuan"}).pretty() where by = 'maxuan'
小于 {<key>:{$lt:<value>}} db.mycol.find({"likes":{$lt:50}}).pretty() where likes < 50
小于等于 {<key>:{$lte:<value>}} db.mycol.find({"likes":{$lte:50}}).pretty() where likes <= 50
大于 {<key>:{$gt:<value>}} db.mycol.find({"likes":{$gt:50}}).pretty() where likes > 50
大于等于 {<key>:{$gte:<value>}} db.mycol.find({"likes":{$gte:50}}).pretty() where likes >= 50
不等于 {<key>:{$ne:<value>}} db.mycol.find({"likes":{$ne:50}}).pretty() where likes != 50
in {<key>:{$in:[<value1>,<value2>,<value3>]}} db.mycol.find({"likes":{$in:[50,51,52]}}).pretty() where likes in(50,51,52)
nin {<key>:{$nin:[<value1>,<value2>,<value3>}} db.mycol.find({"likes":{$nin:[50,51,52]}}).pretty() where likes not in (50,51,52)
模糊查询 {<key>:/xx/} db.mycol.find({"name":/maxuan/}).pretty() where name like "%maxuan%"

下面我们将对上表中的所有操作演示

4、MongoDB中的AND操作符

语法

find()方法中,如果通过使用’‘将它们分开传递多个键,则 MongoDB 将其视为AND条件, 以下是AND的基本语法 -

>db.mycol.find(
   {
      $and: [
         {key1: value1}, {key2:value2}
      ]
   }
).pretty()

示例

以下示例将显示由“maxuan course”编写并且标题为“MongoDB Overview”的所有教程。

> db.mycol.find({$and:[{"by":"maxuan course"},{"title": "MongoDB Overview"}]}).pretty()
{
        "_id" : 100,
        "title" : "MongoDB Overview",
        "description" : "MongoDB is no sql database",
        "by" : "maxuan course",
        "url" : "http://www.maxuan.com",
        "tags" : [
                "mongodb",
                "database",
                "NoSQL"
        ],
        "likes" : 100
}
>

对于上面给出的例子,等效的SQL where子句是 -

SELECT * FROM mycol where by ='maxuan course' AND title ='MongoDB Overview'

可以在find子句中传递任意数量的键值。

5、MongoDB中的OR操作符

语法

在要根据OR条件查询文档,需要使用$or关键字。 以下是OR条件的基本语法 -

>db.mycol.find(
   {
      $or: [
         {key1: value1}, {key2:value2}
      ]
   }
).pretty()

示例

以下示例将显示由“maxuan course”编写或标题为“MongoDB Overview”的所有教程。

>db.mycol.find({$or:[{"by":"maxuan course"},{"title": "MongoDB Overview"}]}).pretty()
{
   "_id": 100,
   "title": "MongoDB Overview", 
   "description": "MongoDB is no sql database",
   "by": "maxuan course",
   "url": "http://www.maxuan.com",
   "tags": ["mongodb", "database", "NoSQL"],
   "likes": "100"
}
>

6、使用 AND 和 OR 条件一起

示例

以下示例将显示likes大于10以及标题是“MongoDB Overview”或者“maxuan course”的所有文档。 等价SQL where子句为 -

SELECT * FROM mycol where likes> 10 AND (by ='maxuan course' OR title ='MongoDB Overview')

>db.mycol.find({"likes": {$gt:10}, $or: [{"by": "maxuan course"},
   {"title": "MongoDB Overview"}]}).pretty()
{
   "_id": 100,
   "title": "MongoDB Overview", 
   "description": "MongoDB is no sql database",
   "by": "maxuan course",
   "url": "http://www.maxuan.com",
   "tags": ["mongodb", "database", "NoSQL"],
   "likes": "100"
}
>

7、查询嵌入/嵌套文档

这里演示如何使用:db.collection.find()方法对嵌入/嵌套文档的查询操作的示例。 此页面上的示例使用inventory集合。要填充库存(inventory)集合以准备一些数据,请运行以下命令:

db.inventory.insertMany( [
   { item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
   { item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "A" },
   { item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },
   { item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },
   { item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" }
]);

匹配嵌入/嵌套文档

要在作为嵌入/嵌套文档的字段上指定相等条件,请使用查询过滤器文档{<field>:<value>},其中<value>是要匹配的文档。

例如,以下查询选择字段size等于{ h: 14, w: 21, uom: "cm" }的所有文档:

db.inventory.find( { size: { h: 14, w: 21, uom: "cm" } } )

整个嵌入式文档中的相等匹配需要精确匹配指定的<value>文档,包括字段顺序。
例如,以下查询与库存(inventory)集合中的任何文档不匹配:

db.inventory.find(  { size: { w: 21, h: 14, uom: "cm" } }  )

查询嵌套字段

要在嵌入/嵌套文档中的字段上指定查询条件,请使用点符号(“field.nestedField”)。

在嵌套字段上指定等于匹配

以下示例选择在size字段中嵌套的字段uom等于“in”的所有文档:

db.inventory.find( { "size.uom": "in" } )

使用查询运算符指定匹配

查询过滤器文档可以使用查询运算符来指定,如以下形式的条件:

{ <field1>: { <operator1>: <value1> }, ... }

以下查询使用size字段中嵌入的字段h中的小于运算符($lt):

db.inventory.find( { "size.h": { $lt: 15 } } )

指定AND条件

以下查询选择嵌套字段h小于15的所有文档,嵌套字段uom等于“in”,status字段等于“D”:

db.inventory.find( { "size.h": { $lt: 15 }, "size.uom": "in", status: "D" } )

十四、MongoDB更新文档

MongoDB的update()save()方法用于将集合中的文档更新,update()方法更新现有文档中的值,而save()方法使用save()方法中传递的文档数据替换现有文档。

1、MongoDB Update()方法

update()方法更新现有文档中的值。

语法

update()方法的基本语法如下 -

> db.COLLECTION_NAME.update(SELECTION_CRITERIA, UPDATED_DATA, ISADD, ISUPDATES)

ISADD:找不到是否新增

ISUPDATE:如果多条记录符合条件,是否修改所有符合条件的记录(默认修改第1条匹配记录)

示例

考虑mycol集合具有以下数据 -

> db.mycol.find({}, {'_id':1, 'title':1})
{ "_id" : 100, "title" : "MongoDB Overview" }
{ "_id" : 101, "title" : "MongoDB Guide" }
{ "_id" : 102, "title" : "NoSQL Database" }
{ "_id" : 104, "title" : "Python Quick Guide" }
>

以下示例将为标题为“MongoDB Overview”的文档设置为“New Update MongoDB Overview”。

> db.mycol.find({'title':'MongoDB Overview'},{'_id':1, 'title':1})
{ "_id" : 100, "title" : "MongoDB Overview" }
> # 更新操作
> db.mycol.update({'title':'MongoDB Overview'},{$set:{'title':'New Update MongoDB Overview'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> # 查询更新后的结果 -
> db.mycol.find({'_id':100},{'_id':1, 'title':1})
{ "_id" : 100, "title" : "New Update MongoDB Overview" }
>

注意:默认情况下,MongoDB只会更新一个文档,要更新多个文档,需要将参数’multi‘设置为true

>db.mycol.update({'title':'MongoDB Overview'},
   {$set:{'title':'New Update MongoDB Overview'}},{multi:true})

其他修改器:

$inc 递增

$rename 修改列名

$set 修改列值(新增列),区别在于value是boolean还是真正的value值

$unset 删除列

十五、MongoDB删除文档

在本章中,我们将学习如何删除 MongoDB 集合中的文档。

1、remove()方法

MongoDB中的 remove()方法用于从集合中删除文档, remove()方法接受两个参数, 一个是删除条件,第二个是标志:justOne

  • criteria - (可选)符合删除条件的集合将被删除。
  • justOne - (可选)如果设置为true1,则只删除一个文档。

语法

remove()方法的基本语法如下 -

>db.COLLECTION_NAME.remove(DELLETION_CRITTERIA)

假设mycol集合具有以下数据。

> db.mycol.find({}, {'_id':1, 'title':1})
{ "_id" : 101, "title" : "MongoDB Guide" }
{ "_id" : 102, "title" : "NoSQL Database" }
{ "_id" : 104, "title" : "Python Quick Guide" }
{ "_id" : 100, "title" : "Update By Save()Method." }
>

以下示例将删除_id为“100”的文档。

> db.mycol.find({}, {'_id':1, 'title':1})
{ "_id" : 101, "title" : "MongoDB Guide" }
{ "_id" : 102, "title" : "NoSQL Database" }
{ "_id" : 104, "title" : "Python Quick Guide" }
{ "_id" : 100, "title" : "Update By Save()Method." }
>
> db.mycol.remove({'_id':100})
WriteResult({ "nRemoved" : 1 })
> db.mycol.find({}, {'_id':1, 'title':1})
{ "_id" : 101, "title" : "MongoDB Guide" }
{ "_id" : 102, "title" : "NoSQL Database" }
{ "_id" : 104, "title" : "Python Quick Guide" }
>

2、只删除一条文档记录

如果有多条记录,并且只想删除第一条记录,则在remove()方法中设置justOne参数。

>db.COLLECTION_NAME.remove(DELETION_CRITERIA,1)

3、删除所有文档记录

删除所有文档记录,可在remove()方法中设置justOne参数。

如果不指定删除条件,MongoDB 将删除集合中的所有文档。 这相当于SQL的truncate命令。

>db.mycol.remove()
>db.mycol.find()
>

十六、MongoDB投影(选择字段)

在MongoDB中,投影表示仅选择所需要字段的数据,而不是选择整个文档字段的数据。例如某个文档有5个字段,但只要显示3个字段。

1、find()方法

MongoDB的find()方法,在 MongoDB [查询文档]中此方法接收的第二个可选参数是要检索的字段列表, 在MongoDB中,当执行find()方法时,它默认将显示文档的所有字段,为了限制显示的字段,需要将字段列表对应的值设置为101用于显示字段,而0用于隐藏字段。

具有投影的find()方法的基本语法如下:

语法

>db.COLLECTION_NAME.find({},{KEY:1})

假设集合mycol有以下数据 -

> db.mycol.find({}, {'_id':1, 'title':1})
{ "_id" : 101, "title" : "MongoDB Guide" }
{ "_id" : 102, "title" : "NoSQL Database" }
{ "_id" : 104, "title" : "Python Quick Guide" }
{ "_id" : 100, "title" : "MongoDB Overview" }
>

以下示例将在查询文档时只显示文档的标题。

> db.mycol.find({}, {'title':1,'_id':0})
{ "title" : "MongoDB Guide" }
{ "title" : "NoSQL Database" }
{ "title" : "Python Quick Guide" }
{ "title" : "MongoDB Overview" }

> db.mycol.find({}, {'title':1,'by':1, 'url':1})
{ "_id" : 101, "title" : "MongoDB Guide", "by" : "maxuan course", "url" : "http://www.maxuan.com" }
{ "_id" : 102, "title" : "NoSQL Database", "by" : "maxuan course", "url" : "http://www.maxuan.com" }
{ "_id" : 104, "title" : "Python Quick Guide", "by" : "maxuan course", "url" : "http://www.maxuan.com" }
{ "_id" : 100, "title" : "MongoDB Overview", "by" : "maxuan course", "url" : "http://www.maxuan.com" }
>

请注意,在执行find()方法时,始终都会显示_id字段,如果不想要此字段,则需要将其设置为0

十七、MongoDB限制记录数

在本章中,我们将学习如何使用MongoDB中的限制记录数量。

1、MongoDB limit()方法

要限制 MongoDB 中返回的记录数,需要使用limit()方法, 该方法接受一个数字类型参数,它是要显示的文档数。

语法

limit()方法的基本语法如下:

> db.COLLECTION_NAME.find().limit(NUMBER)

示例

假设集合myycol有以下数据。

> db.mycol.find({},{'_id':1, 'title':1})
{ "_id" : 101, "title" : "MongoDB Guide" }
{ "_id" : 102, "title" : "NoSQL Database" }
{ "_id" : 104, "title" : "Python Quick Guide" }
{ "_id" : 100, "title" : "MongoDB Overview" }
>

以下示例将在查询文档时仅显示两个文档。

> db.mycol.find({},{"title":1,_id:0}).limit(2)
{ "title" : "MongoDB Guide" }
{ "title" : "NoSQL Database" }
>

如果没有在limit()方法中指定number参数的值,那么它将显示集合中的所有文档。

2、MongoDB skip()方法

除了limit()方法之外,还有一个方法skip()也接受数字类型参数,用于跳过文档数量。

语法

skip()方法的基本语法如下 -

>db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)

示例

以下示例将仅显示第三个文档。

> db.mycol.find({},{"title":1,_id:0}).limit(1).skip(2)
{ "title" : "Python Quick Guide" }
>

请注意,skip()方法中的默认值为0

3、顺序问题

结论:先看 skip和limit, 当两者一起使用的时候, 不管其位置顺序,默认先skip,再limit。

如果再加上sort呢??结合下面的sort一起讲。

十八、MongoDB排序记录

在本章中,我们将学习如何在 MongoDB 中排序记录。

1、MongoDB sort()方法

要在MongoDB中排序文档,需要使用sort()方法, 该方法接受包含字段列表及其排序顺序的文档,使用指定排序顺序1-11用于升序,而-1用于降序。

语法

sort()方法的基本语法如下 -

>db.COLLECTION_NAME.find().sort({KEY:1})

示例

假设集合myycol有以下数据。

> db.mycol.find({},{'_id':1, 'title':1})
{ "_id" : 101, "title" : "MongoDB Guide" }
{ "_id" : 102, "title" : "NoSQL Database" }
{ "_id" : 104, "title" : "Python Quick Guide" }
{ "_id" : 100, "title" : "MongoDB Overview" }
>

以下示例将按标题降序排序显示文档。

> ## 按title降序排序
> db.mycol.find({},{"title":1,_id:0}).sort({"title":-1})
{ "title" : "Python Quick Guide" }
{ "title" : "NoSQL Database" }
{ "title" : "MongoDB Overview" }
{ "title" : "MongoDB Guide" }
> ## 按title升序排序
> db.mycol.find({},{"title":1,_id:0}).sort({"title":1})
{ "title" : "MongoDB Guide" }
{ "title" : "MongoDB Overview" }
{ "title" : "NoSQL Database" }
{ "title" : "Python Quick Guide" }
>

以下示例将按“_id”降序和升序排序显示文档。

> 按“_id”升序排序
> db.mycol.find({},{"title":1,_id:1}).sort({"_id":1})
{ "_id" : 100, "title" : "MongoDB Overview" }
{ "_id" : 101, "title" : "MongoDB Guide" }
{ "_id" : 102, "title" : "NoSQL Database" }
{ "_id" : 104, "title" : "Python Quick Guide" }
> # 按“_id”降序排序
> db.mycol.find({},{"title":1,_id:1}).sort({"_id":-1})
{ "_id" : 104, "title" : "Python Quick Guide" }
{ "_id" : 102, "title" : "NoSQL Database" }
{ "_id" : 101, "title" : "MongoDB Guide" }
{ "_id" : 100, "title" : "MongoDB Overview" }
>

结论:由结果可以得出,当sort,skip,limit一起使用时,无论其位置变化,总是先sort再skip,最后limit。

但是如果非要先跳过,再限制条数 最后才排序怎么办?

可以用aggregate, aggregate有管道流的性质,$skip,$limit,$sort执行顺序跟位置一致,这个后面会讲到。

十九、MongoDB索引

索引支持查询的有效地提高效率,没有索引,MongoDB必须扫描集合的每个文档,以选择与查询语句匹配的文档,这种扫描效率很低,需要 MongoDB 处理大量的数据。

索引是特殊的数据结构,以易于遍历的形式存储数据集的一小部分, 索引存储特定字段或一组字段的值,按照索引中指定的字段值排序。

1、ensureIndex()方法

要创建索引,需要使用MongoDB的ensureIndex()方法。

语法

ensureIndex()方法的基本语法如下 -

>db.COLLECTION_NAME.ensureIndex({KEY:1})

这里的key是要在其上创建索引的字段的名称,1是升序,要按降序创建索引,需要使用-1

示例

>db.mycol.ensureIndex({"title":1})

ensureIndex()方法中,可以传递多个字段,以在多个字段上创建索引。

>db.mycol.ensureIndex({"title":1,"description":-1})
>

ensureIndex()方法也接受选项列表(可选)。 以下是列表 -

参数 类型 描述
background Boolean 在后台构建索引,以便构建索引不会阻止其他数据库活动,则指定background的值为true。默认值为false
unique Boolean 创建一个唯一的索引,使得集合不会接受索引键或键匹配索引中现有值的文档的插入。 指定true以创建唯一索引。 默认值为false
name String 索引的名称。如果未指定,则MongoDB通过连接索引字段的名称和排序顺序来生成索引名称。
dropDups Boolean 在可能有重复项的字段上创建唯一索引。MongoDB仅索引第一次出现的键,并从集合中删除包含该键的后续出现的所有文档。指定true以创建唯一索引。 默认值为false
sparse Boolean 如果为true,则索引仅引用具有指定字段的文档。这些索引在某些情况下(特别是排序)使用的空间较小,但行为不同。默认值为false
expireAfterSeconds integer 指定一个值(以秒为单位)作为TTL,以控制MongoDB在此集合中保留文档的时间。
v 索引版本 索引版本号。默认索引版本取决于创建索引时运行的MongoDB的版本。
weights 文档 权重是从199999之间的数字,并且表示该字段相对于其他索引字段在分数方面的意义。
default_language String 对于文本索引,确定停止词列表的语言以及句柄和分词器的规则。 默认值为英文。
language_override String 对于文本索引,要指定文档中包含覆盖默认语言的字段名称。默认值为language

二十、MongoDB聚合

聚合操作处理数据记录并返回计算结果。 聚合操作将多个文档中的值组合在一起,并可对分组数据执行各种操作,以返回单个结果, 在SQL中的 count(*)group by组合相当于mongodb 中的聚合功能。

1、aggregate()方法

对于MongoDB中的聚合,应该使用aggregate()方法。

语法

aggregate()方法的基本语法如下 -

>db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)

示例

假设在集合中,有以下数据 -

db.article.insert([
{
   _id: 100,
   title: 'MongoDB Overview',
   description: 'MongoDB is no sql database',
   by_user: 'Maxsu',
   url: 'http://www.maxuan.com',
   tags: ['mongodb', 'database', 'NoSQL'],
   likes: 100
},
{
   _id: 101,
   title: 'NoSQL Overview', 
   description: 'No sql database is very fast',
   by_user: 'Maxsu',
   url: 'http://www.maxuan.com',
   tags: ['mongodb', 'database', 'NoSQL'],
   likes: 10
},
{
   _id: 102,
   title: 'Neo4j Overview', 
   description: 'Neo4j is no sql database',
   by_user: 'Kuber',
   url: 'http://www.neo4j.com',
   tags: ['neo4j', 'database', 'NoSQL'],
   likes: 750
},
{
   _id: 103,
   title: 'MySQL Overview', 
   description: 'MySQL is sql database',
   by_user: 'Curry',
   url: 'http://www.maxuan.com/mysql/',
   tags: ['MySQL', 'database', 'SQL'],
   likes: 350
}])

现在从上面的集合中,如果要显示一个列表,说明每个用户写入了多少个教程,那么可使用以下aggregate()方法 -

> db.article.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}])
{ "_id" : "Curry", "num_tutorial" : 1 }
{ "_id" : "Kuber", "num_tutorial" : 1 }
{ "_id" : "Maxsu", "num_tutorial" : 2 }
>

对于上述用例的Sql等效查询是:

select by_user, count(*) as num_tutorial from article group by by_user;

在上面的例子中,我们按字段by_user分组了文档,并且每次发生的by_user的前一个值的值都被递增。以下是可用聚合表达式的列表。

表达式 描述 示例
$sum 从集合中的所有文档中求出定义的值。 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}])
$avg 计算集合中所有文档的所有给定值的平均值。 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}])
$min 从集合中的所有文档获取相应值的最小值。 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}])
$max 从集合中的所有文档获取相应值的最大值。 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}])
$push 将值插入到生成的文档中的数组中。 db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}])
$addToSet 将值插入生成的文档中的数组,但不会创建重复项。 db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}])
$first 根据分组从源文档获取第一个文档。 通常情况下,这只适用于以前应用的“$sort”阶段。 db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}])
$last 根据分组从源文档获取最后一个文档。通常情况下,这只适用于以前应用的“$sort”阶段。 db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}])

2、管道概念

在UNIX命令中,shell管道可以对某些输入执行操作,并将输出用作下一个命令的输入。 MongoDB也在聚合框架中支持类似的概念。每一组输出可作为另一组文档的输入,并生成一组生成的文档(或最终生成的JSON文档在管道的末尾)。这样就可以再次用于下一阶段等等。

以下是在聚合框架可能的阶段 -

  • $project - 用于从集合中选择一些特定字段。
  • $match - 这是一个过滤操作,因此可以减少作为下一阶段输入的文档数量。
  • $group - 这是上面讨论的实际聚合。
  • $sort - 排序文档。
  • $skip - 通过这种方式,可以在给定数量的文档的文档列表中向前跳过。
  • $limit - 限制从当前位置开始的给定数量的文档数量。
  • $unwind - 用于展开正在使用数组的文档。使用数组时,数据是预先加入的,此操作将被撤销,以便再次单独使用文档。 因此,在这个阶段,将增加下一阶段的文件数量。

二十一、MongoDB副本集群原理及搭建

复制是跨多个服务器同步数据的过程,复制提供冗余,并通过不同数据库服务器上的多个数据副本增加数据可用性, 保护数据库免受单个服务器的丢失, 复制还允许从硬件故障和服务中断中恢复, 使用其他数据副本,可以将其专用于灾难恢复,报告或备份。

1、为什么复制?

  • 保持数据安全
  • 数据的高可用性(24 * 7)
  • 灾难恢复
  • 维护无停机(如备份,索引重建,压缩)
  • 读取缩放(额外的副本可读)
  • 副本集(集群架构,主从架构)对应用程序是透明的

2、MongoDB复制的工作原理

MongoDB通过使用副本集来实现复制,副本集是托管相同数据集的一组 mongod 实例, 在一个副本中,一个节点是接收所有写操作的主节点,所有其他实例(例如辅助节点)都应用主节点的操作,以便它们具有相同的数据集。 副本集可以只有一个主节点。

  • 副本集是一组两个或多个节点(通常最少需要3个节点)。
  • 在副本集中,一个节点是主节点,其余节点是次要节点。
  • 所有数据从主节点复制到辅助节点。
  • 在自动故障切换或维护时,选择为主节点建立,并选择新的主节点。
  • 恢复故障节点后,它再次加入副本集,并作为辅助节点。

显示了MongoDB复制的典型图,客户端应用程序始终与主节点进行交互,然后主节点将数据复制到辅助节点。

img

3、副本集功能

  • N个节点的集群
  • 任何一个节点都可以是主节点
  • 所有写入操作都转到主节点操作
  • 自动故障切换
  • 自动恢复
  • 共识一般选举

4、设置副本集

前提:准备三个节点(192.168.0.107,192.168.0.108,192.168.0.109),三个节点上都安装好相同版本的mongodb,且三个节点上27017端口放行。

具体执行如下:

##27017端口放行
firewall-cmd --permanent --add-port=27017/tcp
##防火墙重启
firewall-cmd --reload

1)、静态配置方式

  • 文件配置的方式
    • 三个节点上都需要修改/usr/local/mongodb/mongodb.conf文件,在文件末尾增加一行副本集rs0:replSet=rs0, 执行命令如下:
    vi /usr/local/mongodb/mongodb.conf
    #端口号
    port=27017
    #db目录
    dbpath=/usr/local/mongodb/data
    #日志目录
    logpath=/usr/local/mongodb/logs/mongodb.log
    #后台
    fork=true
    #日志输出
    logappend=true
    #允许远程IP连接(集群时需要修改为实际ip地址)
    bind_ip=192.168.0.107
    #复制集名称
    replSet=rs0

    image-20201009181545091

    • 在192.168.0.107的mongodb根目录下启动mongodb,执行命令如下:
    [root@myshop01 mongodb]# ./bin/mongod --config mongodb.conf
    about to fork child process, waiting until server is ready for connections.
    forked process: 4585
    child process started successfully, parent exiting

    启动成功后,执行客户端命令./bin/mongo 192.168.0.107:27017进入:

    ##注意:此时./bin/mongo命令后面必须加上 ip:端口(集群模式)
    [root@myshop01 mongodb]# ./bin/mongo 192.168.0.107:27017
    MongoDB shell version v4.4.1
    connecting to: mongodb://192.168.0.107:27017/test?compressors=disabled&gssapiServiceName=mongodb
    Implicit session: session { "id" : UUID("70bce868-2541-43d4-b791-517d4ba69fd0") }
    MongoDB server version: 4.4.1
    ---
    The server generated these startup warnings when booting: 
            2022-06-20T05:18:00.191+08:00: ***** SERVER RESTARTED *****
            2022-06-20T05:18:01.808+08:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
            2022-06-20T05:18:01.808+08:00: You are running this process as the root user, which is not recommended
            2022-06-20T05:18:01.808+08:00: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. We suggest setting it to 'never'
            2022-06-20T05:18:01.808+08:00: /sys/kernel/mm/transparent_hugepage/defrag is 'always'. We suggest setting it to 'never'
            2022-06-20T05:18:01.808+08:00: Soft rlimits too low
            2022-06-20T05:18:01.808+08:00:         currentValue: 1028
            2022-06-20T05:18:01.808+08:00:         recommendedMinimum: 64000
    ---
    ---
            Enable MongoDB's free cloud-based monitoring service, which will then receive and display
            metrics about your deployment (disk utilization, CPU, operation statistics, etc).
    
            The monitoring data will be available on a MongoDB website with a unique URL accessible to you
            and anyone you share the URL with. MongoDB may use this information to make product
            improvements and to suggest MongoDB products and deployment options to you.
    
            To enable free monitoring, run the following command: db.enableFreeMonitoring()
            To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
    ---
    rs0:PRIMARY> 

    此时由单机模式下的">" 提示符号变成了"rs0:PRIMARY>" ,此时表示在集群模式下,且当前节点是主节点,主节点只能读和写,而从节点只能读。

    • 定义config变量,注意:此时必须切换到admin库中指定副本集中的节点,配置信息如下:
    rs0:PRIMARY> use admin
    ##rs0副本集中有3个节点:0,1,2 。分别对应主机107,108,109,端口都是27017
    rs0:PRIMARY> config = {"_id":"rs0",
    ...   "members":[
    ...   {"_id":0,host:"192.168.0.107:27017"},
    ...   {"_id":1,host:"192.168.0.108:27017"},
    ...   {"_id":2,host:"192.168.0.109:27017"}
    ...           ]
    ... }
    
    ##该命令强制更新配置(可以覆盖之前的config配置)
    rs0:PRIMARY> rs.reconfig(config,{"force":true})
    {
            "ok" : 1,
            "$clusterTime" : {
                    "clusterTime" : Timestamp(1602234458, 455),
                    "signature" : {
                            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                            "keyId" : NumberLong(0)
                    }
            },
            "operationTime" : Timestamp(1602234458, 455)
    }
    
    ##查看状态
    rs0:PRIMARY> rs.status()
    {
            "set" : "rs0",
            "date" : ISODate("2020-06-19T21:44:40.054Z"),
            "myState" : 2,
            "term" : NumberLong(13),
            "syncSourceHost" : "",
            "syncSourceId" : -1,
            "heartbeatIntervalMillis" : NumberLong(2000),
            "majorityVoteCount" : 2,
            "writeMajorityCount" : 2,
            "votingMembersCount" : 3,
            "writableVotingMembersCount" : 3,
            "optimes" : {
                    "lastCommittedOpTime" : {
                            "ts" : Timestamp(1602234458, 455),
                            "t" : NumberLong(13)
                    },
                    "lastCommittedWallTime" : ISODate("2020-06-19T21:44:22.180Z"),
                    "appliedOpTime" : {
                            "ts" : Timestamp(1602234458, 456),
                            "t" : NumberLong(13)
                    },
                    "durableOpTime" : {
                            "ts" : Timestamp(1602234458, 456),
                            "t" : NumberLong(13)
                    },
                    "lastAppliedWallTime" : ISODate("2020-06-19T21:44:32.181Z"),
                    "lastDurableWallTime" : ISODate("2020-06-19T21:44:32.181Z")
            },
            "lastStableRecoveryTimestamp" : Timestamp(1602234458, 450),
            "members" : [
                    {
                            "_id" : 0,
                            "name" : "192.168.0.107:27017",
                            "health" : 1,
                            "state" : 2,
                            ##此时107是从机状态
                            "stateStr" : "SECONDARY",
                            "uptime" : 180,
                            "optime" : {
                                    "ts" : Timestamp(1602234458, 456),
                                    "t" : NumberLong(13)
                            },
                            "optimeDate" : ISODate("2020-10-09T09:07:38Z"),
                            "syncSourceHost" : "",
                            "syncSourceId" : -1,
                            "infoMessage" : "",
                            "configVersion" : 49451,
                            "configTerm" : -1,
                            "self" : true,
                            "lastHeartbeatMessage" : ""
                    },
                    {
                            "_id" : 1,
                            "name" : "192.168.0.108:27017",
                            "health" : 0,
                            "state" : 8,
                            ##此时108是未知状态(因为还未启动)
                            "stateStr" : "(not reachable/healthy)",
                            "uptime" : 0,
                            "optime" : {
                                    "ts" : Timestamp(0, 0),
                                    "t" : NumberLong(-1)
                            },
                            "optimeDurable" : {
                                    "ts" : Timestamp(0, 0),
                                    "t" : NumberLong(-1)
                            },
                            "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
                            "optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"),
                            "lastHeartbeat" : ISODate("2020-06-19T21:44:39.972Z"),
                            "lastHeartbeatRecv" : ISODate("1970-01-01T00:00:00Z"),
                            "pingMs" : NumberLong(0),
                            "lastHeartbeatMessage" : "Error connecting to 192.168.0.108:27017 :: caused by :: Connection refused",
                            "syncSourceHost" : "",
                            "syncSourceId" : -1,
                            "infoMessage" : "",
                            "configVersion" : -1,
                            "configTerm" : -1
                    },
                    {
                            "_id" : 2,
                            "name" : "192.168.0.109:27017",
                            "health" : 0,
                            "state" : 8,
                            ##此时109也是未知状态(未启动)
                            "stateStr" : "(not reachable/healthy)",
                            "uptime" : 0,
                            "optime" : {
                                    "ts" : Timestamp(0, 0),
                                    "t" : NumberLong(-1)
                            },
                            "optimeDurable" : {
                                    "ts" : Timestamp(0, 0),
                                    "t" : NumberLong(-1)
                            },
                            "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
                            "optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"),
                            "lastHeartbeat" : ISODate("2020-06-19T21:44:39.971Z"),
                            "lastHeartbeatRecv" : ISODate("1970-01-01T00:00:00Z"),
                            "pingMs" : NumberLong(0),
                            "lastHeartbeatMessage" : "Error connecting to 192.168.0.109:27017 :: caused by :: Connection refused",
                            "syncSourceHost" : "",
                            "syncSourceId" : -1,
                            "infoMessage" : "",
                            "configVersion" : -1,
                            "configTerm" : -1
                    }
            ],
            "ok" : 1,
            "$clusterTime" : {
                    "clusterTime" : Timestamp(1602234458, 456),
                    "signature" : {
                            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                            "keyId" : NumberLong(0)
                    }
            },
            "operationTime" : Timestamp(1602234458, 456)
    }
    rs0:SECONDARY> 

    可以看出现在副本集中有三个节点:_id 分别是 0,1,2。0节点是107机器,此时是secondary从节点状态,108和109 都是(not reachable/healthy)状态,因为此时108,109还没有启动。此时陆续启动108,和109。

    108启动如下:

    [root@myshop02 mongodb]# ./bin/mongod --shutdown --dbpath /usr/local/mongodb/data/
    {"t":{"$date":"2020-10-09T18:38:34.448+08:00"},"s":"I",  "c":"CONTROL",  "id":23285,   "ctx":"main","msg":"Automatically disabling TLS 1.0, to force-enable TLS 1.0 specify --sslDisabledProtocols 'none'"}
    {"t":{"$date":"2020-10-09T18:38:34.453+08:00"},"s":"W",  "c":"ASIO",     "id":22601,   "ctx":"main","msg":"No TransportLayer configured during NetworkInterface startup"}
    {"t":{"$date":"2020-10-09T18:38:34.453+08:00"},"s":"I",  "c":"NETWORK",  "id":4648601, "ctx":"main","msg":"Implicit TCP FastOpen unavailable. If TCP FastOpen is required, set tcpFastOpenServer, tcpFastOpenClient, and tcpFastOpenQueueSize."}
    There doesn't seem to be a server running with dbpath: /usr/local/mongodb/data/
    [root@myshop02 mongodb]# ./bin/mongod --config mongodb.conf
    about to fork child process, waiting until server is ready for connections.
    forked process: 2699
    child process started successfully, parent exiting

    启动后在107上执行rs.status()查看状态,结果如下:

    rs0:SECONDARY> rs.status()
    {
            "set" : "rs0",
            "date" : ISODate("2020-06-19T22:45:04.329Z"),
            "myState" : 1,
            "term" : NumberLong(14),
            "syncSourceHost" : "",
            "syncSourceId" : -1,
            "heartbeatIntervalMillis" : NumberLong(2000),
            "majorityVoteCount" : 2,
            "writeMajorityCount" : 2,
            "votingMembersCount" : 3,
            "writableVotingMembersCount" : 3,
            "optimes" : {
                    "lastCommittedOpTime" : {
                            "ts" : Timestamp(1602234458, 461),
                            "t" : NumberLong(14)
                    },
                    "lastCommittedWallTime" : ISODate("2020-06-19T22:44:55.956Z"),
                    "readConcernMajorityOpTime" : {
                            "ts" : Timestamp(1602234458, 461),
                            "t" : NumberLong(14)
                    },
                    "readConcernMajorityWallTime" : ISODate("2020-06-19T22:44:55.956Z"),
                    "appliedOpTime" : {
                            "ts" : Timestamp(1602234458, 461),
                            "t" : NumberLong(14)
                    },
                    "durableOpTime" : {
                            "ts" : Timestamp(1602234458, 461),
                            "t" : NumberLong(14)
                    },
                    "lastAppliedWallTime" : ISODate("2020-06-19T22:44:55.956Z"),
                    "lastDurableWallTime" : ISODate("2020-06-19T22:44:55.956Z")
            },
            "lastStableRecoveryTimestamp" : Timestamp(1602234458, 460),
            "electionCandidateMetrics" : {
                    "lastElectionReason" : "electionTimeout",
                    "lastElectionDate" : ISODate("2020-06-19T22:44:25.847Z"),
                    "electionTerm" : NumberLong(14),
                    "lastCommittedOpTimeAtElection" : {
                            "ts" : Timestamp(1602234458, 455),
                            "t" : NumberLong(13)
                    },
                    "lastSeenOpTimeAtElection" : {
                            "ts" : Timestamp(1602234458, 456),
                            "t" : NumberLong(13)
                    },
                    "numVotesNeeded" : 2,
                    "priorityAtElection" : 1,
                    "electionTimeoutMillis" : NumberLong(10000),
                    "numCatchUpOps" : NumberLong(0),
                    "newTermStartDate" : ISODate("2020-06-19T22:44:25.948Z"),
                    "wMajorityWriteAvailabilityDate" : ISODate("2020-06-19T22:44:27.392Z")
            },
            "members" : [
                    {
                            "_id" : 0,
                            "name" : "192.168.0.107:27017",
                            "health" : 1,
                            "state" : 1,
                            ##108加进来之后,重新选举107为主机状态
                            "stateStr" : "PRIMARY",
                            "uptime" : 3804,
                            "optime" : {
                                    "ts" : Timestamp(1602234458, 461),
                                    "t" : NumberLong(14)
                            },
                            "optimeDate" : ISODate("2020-10-09T09:07:38Z"),
                            "syncSourceHost" : "",
                            "syncSourceId" : -1,
                            "infoMessage" : "",
                            "electionTime" : Timestamp(1602234458, 457),
                            "electionDate" : ISODate("2020-10-09T09:07:38Z"),
                            "configVersion" : 49451,
                            "configTerm" : -1,
                            "self" : true,
                            "lastHeartbeatMessage" : ""
                    },
                    {
                            "_id" : 1,
                            "name" : "192.168.0.108:27017",
                            "health" : 1,
                            "state" : 2,
                            ##108此时是从机状态
                            "stateStr" : "SECONDARY",
                            "uptime" : 40,
                            "optime" : {
                                    "ts" : Timestamp(1602234458, 461),
                                    "t" : NumberLong(14)
                            },
                            "optimeDurable" : {
                                    "ts" : Timestamp(1602234458, 461),
                                    "t" : NumberLong(14)
                            },
                            "optimeDate" : ISODate("2020-10-09T09:07:38Z"),
                            "optimeDurableDate" : ISODate("2020-10-09T09:07:38Z"),
                            "lastHeartbeat" : ISODate("2020-06-19T22:45:03.986Z"),
                            "lastHeartbeatRecv" : ISODate("2020-06-19T22:45:03.419Z"),
                            "pingMs" : NumberLong(1),
                            "lastHeartbeatMessage" : "",
                            "syncSourceHost" : "192.168.0.107:27017",
                            "syncSourceId" : 0,
                            "infoMessage" : "",
                            "configVersion" : 49451,
                            "configTerm" : -1
                    },
                    {
                            "_id" : 2,
                            "name" : "192.168.0.109:27017",
                            "health" : 0,
                            "state" : 8,
                            ##109此时还未启动,所以是未知状态
                            "stateStr" : "(not reachable/healthy)",
                            "uptime" : 0,
                            "optime" : {
                                    "ts" : Timestamp(0, 0),
                                    "t" : NumberLong(-1)
                            },
                            "optimeDurable" : {
                                    "ts" : Timestamp(0, 0),
                                    "t" : NumberLong(-1)
                            },
                            "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
                            "optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"),
                            "lastHeartbeat" : ISODate("2020-06-19T22:45:04.040Z"),
                            "lastHeartbeatRecv" : ISODate("1970-01-01T00:00:00Z"),
                            "pingMs" : NumberLong(0),
                            "lastHeartbeatMessage" : "Error connecting to 192.168.0.109:27017 :: caused by :: Connection refused",
                            "syncSourceHost" : "",
                            "syncSourceId" : -1,
                            "infoMessage" : "",
                            "configVersion" : -1,
                            "configTerm" : -1
                    }
            ],
            "ok" : 1,
            "$clusterTime" : {
                    "clusterTime" : Timestamp(1602234458, 461),
                    "signature" : {
                            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                            "keyId" : NumberLong(0)
                    }
            },
            "operationTime" : Timestamp(1602234458, 461)
    }
    rs0:PRIMARY> 

    由以上信息可知,107此时已经是主节点状态(PRIMARY),而108此时是从机状态(SECONDARY),109此时还是(not reachable/healthy)未知状态(因为此时还没启动109)。

    109启动如下:

    [root@myshop03 mongodb]# ./bin/mongod --config mongodb.conf
    about to fork child process, waiting until server is ready for connections.
    forked process: 2712
    child process started successfully, parent exiting
    [root@myshop03 mongodb]# 

    启动后继续在107上执行rs.status()查看状态,结果如下:

    rs0:PRIMARY> rs.status()
    {
            "set" : "rs0",
            "date" : ISODate("2020-06-19T22:50:31.994Z"),
            "myState" : 1,
            "term" : NumberLong(14),
            "syncSourceHost" : "",
            "syncSourceId" : -1,
            "heartbeatIntervalMillis" : NumberLong(2000),
            "majorityVoteCount" : 2,
            "writeMajorityCount" : 2,
            "votingMembersCount" : 3,
            "writableVotingMembersCount" : 3,
            "optimes" : {
                    "lastCommittedOpTime" : {
                            "ts" : Timestamp(1602234458, 494),
                            "t" : NumberLong(14)
                    },
                    "lastCommittedWallTime" : ISODate("2020-06-19T22:50:25.992Z"),
                    "readConcernMajorityOpTime" : {
                            "ts" : Timestamp(1602234458, 494),
                            "t" : NumberLong(14)
                    },
                    "readConcernMajorityWallTime" : ISODate("2020-06-19T22:50:25.992Z"),
                    "appliedOpTime" : {
                            "ts" : Timestamp(1602234458, 494),
                            "t" : NumberLong(14)
                    },
                    "durableOpTime" : {
                            "ts" : Timestamp(1602234458, 494),
                            "t" : NumberLong(14)
                    },
                    "lastAppliedWallTime" : ISODate("2020-06-19T22:50:25.992Z"),
                    "lastDurableWallTime" : ISODate("2020-06-19T22:50:25.992Z")
            },
            "lastStableRecoveryTimestamp" : Timestamp(1602234458, 490),
            "electionCandidateMetrics" : {
                    "lastElectionReason" : "electionTimeout",
                    "lastElectionDate" : ISODate("2020-06-19T22:44:25.847Z"),
                    "electionTerm" : NumberLong(14),
                    "lastCommittedOpTimeAtElection" : {
                            "ts" : Timestamp(1602234458, 455),
                            "t" : NumberLong(13)
                    },
                    "lastSeenOpTimeAtElection" : {
                            "ts" : Timestamp(1602234458, 456),
                            "t" : NumberLong(13)
                    },
                    "numVotesNeeded" : 2,
                    "priorityAtElection" : 1,
                    "electionTimeoutMillis" : NumberLong(10000),
                    "numCatchUpOps" : NumberLong(0),
                    "newTermStartDate" : ISODate("2020-06-19T22:44:25.948Z"),
                    "wMajorityWriteAvailabilityDate" : ISODate("2020-06-19T22:44:27.392Z")
            },
            "members" : [
                    {
                            "_id" : 0,
                            "name" : "192.168.0.107:27017",
                            "health" : 1,
                            "state" : 1,
                            ##109启动后,此时107依然是主机状态
                            "stateStr" : "PRIMARY",
                            "uptime" : 4131,
                            "optime" : {
                                    "ts" : Timestamp(1602234458, 494),
                                    "t" : NumberLong(14)
                            },
                            "optimeDate" : ISODate("2020-10-09T09:07:38Z"),
                            "syncSourceHost" : "",
                            "syncSourceId" : -1,
                            "infoMessage" : "",
                            "electionTime" : Timestamp(1602234458, 457),
                            "electionDate" : ISODate("2020-10-09T09:07:38Z"),
                            "configVersion" : 49451,
                            "configTerm" : -1,
                            "self" : true,
                            "lastHeartbeatMessage" : ""
                    },
                    {
                            "_id" : 1,
                            "name" : "192.168.0.108:27017",
                            "health" : 1,
                            "state" : 2,
                            ##108依旧是从机状态
                            "stateStr" : "SECONDARY",
                            "uptime" : 367,
                            "optime" : {
                                    "ts" : Timestamp(1602234458, 494),
                                    "t" : NumberLong(14)
                            },
                            "optimeDurable" : {
                                    "ts" : Timestamp(1602234458, 494),
                                    "t" : NumberLong(14)
                            },
                            "optimeDate" : ISODate("2020-10-09T09:07:38Z"),
                            "optimeDurableDate" : ISODate("2020-10-09T09:07:38Z"),
                            "lastHeartbeat" : ISODate("2020-06-19T22:50:30.405Z"),
                            "lastHeartbeatRecv" : ISODate("2020-06-19T22:50:31.804Z"),
                            "pingMs" : NumberLong(0),
                            "lastHeartbeatMessage" : "",
                            "syncSourceHost" : "192.168.0.107:27017",
                            "syncSourceId" : 0,
                            "infoMessage" : "",
                            "configVersion" : 49451,
                            "configTerm" : -1
                    },
                    {
                            "_id" : 2,
                            "name" : "192.168.0.109:27017",
                            "health" : 1,
                            "state" : 2,
                            ##109也是从机状态
                            "stateStr" : "SECONDARY",
                            "uptime" : 61,
                            "optime" : {
                                    "ts" : Timestamp(1602234458, 494),
                                    "t" : NumberLong(14)
                            },
                            "optimeDurable" : {
                                    "ts" : Timestamp(1602234458, 494),
                                    "t" : NumberLong(14)
                            },
                            "optimeDate" : ISODate("2020-10-09T09:07:38Z"),
                            "optimeDurableDate" : ISODate("2020-10-09T09:07:38Z"),
                            "lastHeartbeat" : ISODate("2020-06-19T22:50:30.718Z"),
                            "lastHeartbeatRecv" : ISODate("2020-06-19T22:50:31.176Z"),
                            "pingMs" : NumberLong(0),
                            "lastHeartbeatMessage" : "",
                            "syncSourceHost" : "192.168.0.108:27017",
                            "syncSourceId" : 1,
                            "infoMessage" : "",
                            "configVersion" : 49451,
                            "configTerm" : -1
                    }
            ],
            "ok" : 1,
            "$clusterTime" : {
                    "clusterTime" : Timestamp(1602234458, 494),
                    "signature" : {
                            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                            "keyId" : NumberLong(0)
                    }
            },
            "operationTime" : Timestamp(1602234458, 494)
    }
    rs0:PRIMARY> 

    由以上信息可以看出,此时109也已经加入集群,此时状态为从机状态(SECONDARY)。所以此时107,108,109就是个完整的集群,107为主机,108,109为从机,是个典型的1主2从的架构。

    • 验证复制功能

    在107节点上的test库下创建person集合,并插入一个文档。

    rs0:PRIMARY> show collections
    rs0:PRIMARY> db.person.insert({name:"maxuan",addr:"nanjing"})
    WriteResult({ "nInserted" : 1 })
    rs0:PRIMARY> 

    image-20201009200755475

    到108,和109上查看person集合有没有复制过来,注意:这里需要首先执行:rs.secondaryOk(true)

    下图可见108,109都已经成功复制过来了。

    image-20201009200533458

    image-20201009200719798

  • 命令配置的方式

    命令配置的方式实际就是在启动的时候命令行加上--replSet rs0 参数,该参数不用在配置文件中设置。命令方式和文件配置方式的差异就在这里,除了这个差别以为其余都是一样的,这里就不再赘述,直接看视频演示即可。

2)、动态添加节点方式

MongoDB 实例转换为副本集,要转换为副本集,以下是步骤:

  • 关机正在运行 MongoDB 服务器。
  • 通过指定 - replSet选项启动 MongoDB服 务器。 以下是--replSet的基本语法:
mongod --port "PORT" --dbpath "YOUR_DB_DATA_PATH" --replSet "REPLICA_SET_INSTANCE_NAME"

示例

mongod --port 27017 --dbpath "D:\set up\mongodb\data" --replSet rs0
  • 它在端口27017上启动名称为rs0的 mongod 实例。
  • 现在启动命令提示符并连接到这个 mongod 实例。
  • 在Mongo客户端中,发出命令rs.initiate()以启动新的副本集。
  • 要检查副本集配置,可使用命令rs.conf()
  • 要检查复制集的状态,请使用命令rs.status()

5、将会员添加到副本集

要将成员添加到副本集,请在多台计算机上启动 mongod 实例。 现在启动一个 mongo 客户端并发出一个命令rs.add()

语法

rs.add()命令的基本语法如下:

>rs.add(HOST_NAME:PORT)

示例

假设您的 mongod 实例名称是 myshop02,或者ip:192.168.0.108,它在端口 27017 上运行。要将此实例添加到副本集,请在 Mongo 客户端中发出命令 rs.add()

>rs.add("myshop02:27017")
>
##或者
>rs.add("192.168.0.108:27017")
>

只能在连接到主节点时,将 mongod 实例添加到副本集,要检查是否连接到主服务器,请在 mongo 客户端中发出命令db.isMaster()

rs0:PRIMARY> db.isMaster()
{
        "topologyVersion" : {
                "processId" : ObjectId("5eed0e5971861932ea57d89d"),
                "counter" : NumberLong(6)
        },
        "hosts" : [
                "192.168.0.107:27017",
                "192.168.0.108:27017",
                "192.168.0.109:27017"
        ],
        "setName" : "rs0",
        "setVersion" : 1,
        "ismaster" : true,
        "secondary" : false,
        "primary" : "192.168.0.107:27017",
        "me" : "192.168.0.107:27017",
        "electionId" : ObjectId("7fffffff0000000000000001"),
        "lastWrite" : {
                "opTime" : {
                        "ts" : Timestamp(1592595487, 1),
                        "t" : NumberLong(1)
                },
                "lastWriteDate" : ISODate("2020-06-19T19:38:07Z"),
                "majorityOpTime" : {
                        "ts" : Timestamp(1592595487, 1),
                        "t" : NumberLong(1)
                },
                "majorityWriteDate" : ISODate("2020-06-19T19:38:07Z")
        },
        "maxBsonObjectSize" : 16777216,
        "maxMessageSizeBytes" : 48000000,
        "maxWriteBatchSize" : 100000,
        "localTime" : ISODate("2020-06-19T19:38:08.478Z"),
        "logicalSessionTimeoutMinutes" : 30,
        "connectionId" : 36,
        "minWireVersion" : 0,
        "maxWireVersion" : 9,
        "readOnly" : false,
        "ok" : 1,
        "$clusterTime" : {
                "clusterTime" : Timestamp(1592595487, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1592595487, 1)
}

具体操作见视频演示!

二十二、MongoDB分片集群原理及搭建(3+3模式,5虚拟机)

本专题篇幅较长,放在高级课程中讲解,基础课程中暂时不讲。

二十三、MongoDB备份与恢复

本章将介绍如何在MongoDB中创建备份,以及如何恢复数据。

1、导出转储MongoDB数据

要在MongoDB中创建数据库备份,应该使用 mongodump 命令, 此命令将导出转储服务器的整个数据到转储目录,有许多选项可用于限制数据量或创建远程服务器的备份。

语法

mongodump命令的基本语法如下:

> mongodump

示例

启动 mongod 服务器 假设您的 mongod 服务器正在本地主机和端口 27017 上运行,请打开命令提示符并转到 mongodb 实例的 bin 目录(如示例安装路径:D:\MongoDB\Server\4.2\bin),然后键入命令:mongodump

考虑 mycol 集合具有以下数据 -

> db.mycol.find({}, {"_id":1, "title":1})
{ "_id" : 101, "title" : "MongoDB Guide" }
{ "_id" : 102, "title" : "NoSQL Database" }
{ "_id" : 104, "title" : "Python Quick Guide" }
{ "_id" : 100, "title" : "MongoDB Overview" }
>

现在使用以下命令,创建备份 -

> mongodump

该命令将连接到运行在 127.0.0.1 和端口 27017 的服务器,并将服务器的所有数据恢复到目录/bin/dump/。 以下是命令的输出:

D:\>mongodump
2020-10-10T10:24:01.959+0800    writing admin.system.version to dump\admin\syste
m.version.bson
2020-10-10T10:24:02.004+0800    done dumping admin.system.version (1 document)
2020-10-10T10:24:02.005+0800    writing test.items to dump\test\items.bson
2020-10-10T10:24:02.007+0800    done dumping test.items (2 documents)
2020-10-10T10:24:02.306+0800    writing test.test1 to dump\test\test1.bson
2020-10-10T10:24:02.308+0800    done dumping test.test1 (1 document)

此时你可能想知道,上面导出的备份文件放到什么地方了?

默认情况下,MongoDB 会在当前目录下创建一个 dump 目录,并把所有的数据库按数据库名称创建目录,在这个实例中,有两数据库 admintest,那么它将创建两个目录。

怎么样知道 MongoDB 文件的位置?

对于大部分软件,尤其是 Linux平台上的软件,都有一个相关的配置文件,因此任何的设置选项都可以从这个文件中找到,配置文件的一般在 /etc 目录下,所以,mongodb 的配置文件在 /etc/mongod.confmongod.conf配置的内容如下 -

# mongod.conf

# for documentation of all options, see:
#   http://docs.mongodb.org/manual/reference/configuration-options/

# Where and how to store data.
storage:
  dbPath: /var/lib/mongodb
  journal:
    enabled: true
#  engine:
#  mmapv1:
#  wiredTiger:

# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log

# network interfaces
net:
  port: 27017
  bindIp: 127.0.0.1

#processManagement:
#security:
#operationProfiling:
#replication:
#sharding:
## Enterprise-Only Options:
#auditLog:
#snmp:

以下是可用于 mongodump 命令的可用选项的列表。

语法 描述 示例
mongodump —host HOST_NAME —port PORT_NUMBER 此命令将备份指定的 mongod 实例的所有数据库。 mongodump --host 127.0.0.1 --port 27017
mongodump —out BACKUP_DIRECTORY 此命令将仅在指定路径上备份数据库。 mongodump --out /home/maxuan/mongobak
mongodump —collection COLLECTION —db DB_NAME 此命令将仅备份指定数据库的指定集合。 mongodump --collection mycol --db test

2、恢复数据

要恢复备份数据,使用MongoDB的 mongorestore 命令。 此命令从备份目录中恢复所有数据。

语法

mongorestore命令的基本语法是 -

> mongorestore dump/

在恢复数据之前,先删除当前数据库的部分数据,以演示导入恢复数据后可以查询到备份时的数据。

> db.mycol.remove({})
WriteResult({ "nRemoved" : 4 })
>
> db.mycol.find({})
>
>

执行恢复命令后,重新查询数据 -

> db.mycol.find({}, {"title":1})
{ "_id" : 101, "title" : "MongoDB Guide" }
{ "_id" : 102, "title" : "NoSQL Database" }
{ "_id" : 104, "title" : "Python Quick Guide" }
{ "_id" : 100, "title" : "MongoDB Overview" }
>

恢复如下:

D:\>mongorestore dump/
2020-10-10T10:30:39.479+0800    preparing collections to restore from
2020-10-10T10:30:39.522+0800    reading metadata for test.items from dump\test\i
tems.metadata.json
2020-10-10T10:30:39.522+0800    reading metadata for test.test1 from dump\test\t
est1.metadata.json
2020-10-10T10:30:39.542+0800    restoring test.items from dump\test\items.bson
2020-10-10T10:30:39.544+0800    no indexes to restore
2020-10-10T10:30:39.544+0800    finished restoring test.items (2 documents, 0 fa
ilures)
2020-10-10T10:30:39.845+0800    restoring test.test1 from dump\test\test1.bson
2020-10-10T10:30:39.846+0800    no indexes to restore
2020-10-10T10:30:39.846+0800    finished restoring test.test1 (1 document, 0 fai
lures)
2020-10-10T10:30:39.847+0800    3 document(s) restored successfully. 0 document(

二十四、Java连接MongoDB操作

在本章中,我们将学习如何设置和使用MongoDB JDBC驱动程序,之前的课程没有给mongodb增加用户和密码,本节课首先添加用户和密码。

1)、添加管理用户

mongoDB 没有超级用户root,只有能管理用户的用户userAdminAnyDatabase,所以必须首先创建这个用户,且必须在admin库下操作,代码如下:

> use admin
> db.createUser( {user: "admin",pwd: "123456",roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]})

注:添加完用户后可以使用show users或db.system.users.find()查看已有用户

2)、关闭mongodb

添加完管理用户后,关闭MongoDB,并使用权限方式再次开启MongoDB,这里注意不要使用kill直接去杀掉mongodb进程,(如果这样做了,请去data/db目录下删除mongo.lock文件),可以使用db.shutdownServer()关闭。

3)、使用权限方式启动MongoDB

mongod --dbpath=D:\MongoDB\Server\4.2\data --logpath=D:\MongoDB\Server\4.2\log\mongod.log --auth

##或者在配置文件中修改:
auth = true
#noauth = true

4)、对admin用户授权

> use admin
> db.auth("admin","123456") 

5)、创建操作用户

验证之后还是做不了操作,因为admin只有用户管理权限,下面创建用户,用户都跟着库走的。

 > use test

 > db.createUser({user: "root",pwd: "123456",roles: [{ role: "readWrite", db: "test" }]})

6)、使用创建的用户root登录进行数据库操作

mongo 127.0.0.1/test -uroot -p
##输入密码即可

1、创建名为mongo-pro的maven工程

使用IDEA创建一个Maven工程 - mongo-pro ,其目录结果如下所示 -

image-20201010205454461

pom.xml 文件的内容如下 -

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.maxuan</groupId>
    <artifactId>mongo-pro</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongodb-driver-sync</artifactId>
            <version>4.1.0</version>
        </dependency>
    </dependencies>
    <build>
        <defaultGoal>compile</defaultGoal>
    </build>
</project>

以下是连接到数据库的代码片段 -

package com.maxuan;

import com.mongodb.client.*;
import com.mongodb.client.model.Filters;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.InsertManyResult;
import com.mongodb.client.result.UpdateResult;
import org.bson.Document;

import java.util.ArrayList;

/******************************
 *
 * 码炫课堂技术交流Q群:963060292
 * 主讲:smart哥
 *
 ******************************/
public class App {
    public static void main(String[] args) {
        //连接到mongodb服务器
//        MongoClients.create("mongodb://maxuan:123456@localhost:27017/godb");
        MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017/?authSource=test");

        // 连接到test库
        MongoDatabase mgdb = mongoClient.getDatabase("test");

        System.out.println("Connect to database successfully!");
        System.out.println("MongoDatabase inof is : " + mgdb.getName());
        // 如果是安全模式,则必须用户名和密码认证
        // boolean auth = db.authenticate(myUserName, myPassword);
        // System.out.println("Authentication: "+auth);

//        getCollections(mgdb);

        //  createCollection(mgdb);
//        new App().createDocument(mgdb);
//        new App().deleteDocument(mgdb);
        new App().updateDocument(mgdb);
    }
}

默认认证机制

String user; // the user name
String database; // the name of the database in which the user is defined
char[] password; // the password as a character array
// ...
MongoCredential credential = MongoCredential.createCredential(user, database, password);
MongoClient mongoClient = new MongoClient(new ServerAddress("host1", 27017),
                                         Arrays.asList(credential));

或者使用连接字符串而不明确指定认证机制:

MongoClientURI uri = new MongoClientURI("mongodb://user1:pwd1@host1/?authSource=db1");
MongoClient mongoClient = new MongoClient(uri);

执行上面代码,得到以下结果 -

com.mongodb.diagnostics.logging.JULLogger log
信息: Cluster created with settings {hosts=[localhost:27017], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500}
Connect to database successfully!
MongoDatabase inof is : mycol

3、创建和列出集合

要创建集合,可使用 com.mongodb.DB 类的 createCollection()方法。

以下是创建集合的代码片段 -

/**
     * 获取结合列表
     * @param mgdb
     */
    public void getCollections(MongoDatabase mgdb) {
        MongoCollection<Document> coll = mgdb.getCollection("items");

        System.out.println("Collection created successfully");

        System.out.println("当前数据库中的所有集合是:");

        /**
         * 集合列表
         */
        for (String name : mgdb.listCollectionNames()) {
            System.out.println(name);
        }

        long l = coll.countDocuments();
        System.out.println("l==" + l);
    }

4、插入文档

要将文档插入到MongoDB中,使用com.mongodb.DBCollection类的insertOne()方法。

以下是插入文档的代码片段 -

 /**
     * 插入文档
     */
    public void createDocument(MongoDatabase mgdb) {
        MongoCollection<Document> items = mgdb.getCollection("items");
        /**
         * 插入单条记录
         */
//        Document document = new Document().append("_id", 9996)
//                .append("name", "maxuan")
//                .append("addr", "shanghai");
//        InsertOneResult result = items.insertOne(document);

        /**
         * 插入多条记录
         */
        ArrayList<Document> documents = new ArrayList<>();
        documents.add(new Document().append("name", "maxuan1").append("addr", "shandong"));
        documents.add(new Document().append("name", "maxuan2").append("addr", "shanxi"));
        InsertManyResult result = items.insertMany(documents);
        queryDocument(mgdb, "items");
    }

5、更新文档

要从集合更新文档,使用com.mongodb.DBCollection类的update()updateMany()方法。以下是选择第一个文档的代码片段 -

 /**
     * 更新文档
     * @param mgdb
     */
    public void updateDocument(MongoDatabase mgdb) {
        MongoCollection<Document> items = mgdb.getCollection("items");
        /**
         * 更新1条
         */
//        UpdateResult result = items.updateOne(Filters.eq("_id", 9999), new Document("$set", new Document("addr", "beijing")));

        /**
         * 更新多条
         */
        UpdateResult result = items.updateMany(Filters.eq("addr", "shanghai"), new Document("$set", new Document("name", "maxuan3")));
        long count = result.getModifiedCount();
        System.out.println("更新了 "+count+" 条记录!");
        queryDocument(mgdb, "items");
    }

6、删除文档

要从集合中删除第一个文档,需要首先使用findOne()方法选择文档,然后使用com.mongodb.DBCollection类的remove()方法。

以下是删除第一个文档的代码片段 -

/**
     * 删除文档
     * @param mgdb
     */
    public void deleteDocument(MongoDatabase mgdb) {
        MongoCollection<Document> items = mgdb.getCollection("items");
        /**
         * 删除1条
         */
//        DeleteResult result = items.deleteOne(Filters.eq("_id", 9998));

        /**
         * 删除多条
         */
        DeleteResult result = items.deleteMany(Filters.eq("name", "maxuan1"));
        long count = result.getDeletedCount();
        System.out.println("删除了 " + count + " 条记录!");
        queryDocument(mgdb, "items");
    }

课程目录

1、MongoDB与关系型数据库的区别(25:47)

2、MongoDB的特点及使用场景(14:06)

3、MongoDB安装配置(Windows)(18:39)

4、MongoDB安装配置(RedHat,CentOS)(16:37)

5、MongoDB数据建模(14:51)

6、MongoDB创建,删除数据库(12:03)

7、MongoDB创建,删除集合(16:11)

8、MongoDB数据类型及插入文档操作1(15:48)

9、MongoDB插入文档操作2及图形工具操作(14:23)

10、MongoDB查询文档-find()简单查询(13:03)

11、MongoDB查询文档-MongoDB与RDBMS的等效Where子句1(13:28)

12、MongoDB查询文档-MongoDB与RDBMS的等效Where子句2(15:32)

13、MongoDB查询文档-嵌套查询(11:02)

14、MongoDB查询文档-模糊查询&更新文档$set操作(17:17)

15、MongoDB更新文档-$inc,$rename,$unset等操作(07:30)

16、MongoDB删除文档(06:40)

17、MongoDB投影(选择字段)(06:13)

18、MongoDB限制记录数(limit,skip等操作)(12:56)

19、MongoDB排序记录(sort等综合操作)(08:49)

20、MongoDB索引(06:17)

21、MongoDB聚合操作-aggregate基本操作(16:51)

22、MongoDB聚合操作-aggregate管道综合操作(25:24)

23、MongoDB副本集群原理及搭建-集群架构演变(16:38)

24、MongoDB副本集群原理及搭建-3节点副本集群实战1(18:23)

25、MongoDB副本集群原理及搭建-3节点副本集群实战2(17:53)

26、MongoDB副本集群原理及搭建-动态添加节点(10:40)

27、MongoDB备份与恢复(11:42)

28、Java连接MongoDB操作-monggodb权限设置(14:52)

29、Java连接MongoDB操作-查询,新增文档(20:38)

30、Java连接MongoDB操作-删除,更新文档(27:27)