MongoDB快速实战与基本原理

MongoDB 介绍

什么是 MongoDB

MongoDB 是一个文档数据库(以 JSON 为数据模型),由 C++ 语言编写,旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
文档来自于“JSON Document”,并非我们一般理解的 PDF、WORD 文档。
MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,数据格式是 BSON,一种类似 JSON 的二进制形式的存储格式,简称 Binary JSON,和 JSON 一样支持内嵌的文档对象和数组对象,因此可以存储比较复杂的数据类型。Mongo 最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。原则上 Oracle 和 MySQL 能做的事情,MongoDB 都能做(包括 ACID 事务)。
MongoDB 在数据库总排名第 5,仅次于 Oracle、MySQL 等 RDBMS,在 NoSQL 数据库排名首位。从诞生以来,其项目应用广度、社区活跃指数持续上升。

数据库排名网站:https://db-engines.com/en/ranking

image.png

MongoDB6.0 新特性

该版本的主要功能特性包括:

  • 时序集合增强
  • Change Stream 增强
  • 可查询加密
  • 聚合&query 能力增强
  • 集群同步

官网关于升级到 MongoDB6.0 的原因:https://www.mongodb.com/blog/post/big-reasons-upgrade-mongodb-6-0
官方文档:https://www.mongodb.com/docs/v6.0/
MongoDB6.0 发行版本说明:https://www.mongodb.com/docs/v6.0/release-notes/6.0/
阿里云关于 MongoDB6.0 新特性说明:https://help.aliyun.com/document_detail/462614.html?spm=a2c4g.312011.0.0.75b42ab8s9NasS#section-hvy-d22-stk

MongoDB vs 关系型数据库

MongoDB 概念与关系型数据库(RDBMS)非常类似:

SQL 概念MongoDB 概念
数据库(database)数据库(database)
表(table)集合(collection)
行(row)文档(document)
列(column)字段(field)
索引(index)索引(index)
主键(primary key)_id(字段)
视图(view)视图(view)
表连接(table joins)聚合操作($lookup)
  • 数据库(database):最外层的概念,可以理解为逻辑上的名称空间,一个数据库包含多个不同名称的集合。
  • 集合(collection):相当于SQL中的表,一个集合可以存放多个不同的文档。
  • 文档(document):一个文档相当于数据表中的一行,由多个不同的字段组成。
  • 字段(field):文档中的一个属性,等同于列(column)。
  • 索引(index):独立的检索式数据结构,与 SQL 概念一致。
  • _id:每个文档中都拥有一个唯一的 _id 字段,相当于 SQL 中的主键(primary key)。
  • 视图(view):可以看作一种虚拟的(非真实存在的)集合,与 SQL 中的视图类似。从 MongoDB3.4 版本开始提供了视图功能,其通过聚合管道技术实现。
  • 聚合操作($lookup):MongoDB 用于实现“类似”表连接(tablejoin)的聚合操作符。

尽管这些概念大多与 SQL 标准定义类似,但 MongoDB 与传统 RDBMS 仍然存在不少差异,包括:

  • 半结构化

在一个集合中,文档所拥有的字段并不需要是相同的,而且也不需要对所用的字段进行声明。因此,MongoDB 具有很明显的半结构化特点。除了松散的表结构,文档还可以支持多级的嵌套、数组等灵活的数据类型,非常契合面向对象的编程模型。

  • 弱关系

MongoDB 没有外键的约束,也没有非常强大的表连接能力。类似的功能需要使用聚合管道技术来弥补。

MongoDB 技术优势

MongoDB 基于灵活的 JSON 文档模型,非常适合敏捷式的快速开发。与此同时,其与生俱来的高可用、高水平扩展能力使得它在处理海量、高并发的数据应用时颇具优势。

  • JSON 结构和对象模型接近,开发代码量低
  • JSON 的动态模型意味着更容易响应新的业务需求
  • 复制集提供 99.999% 高可用
  • 分片架构支持海量数据和无缝扩容

MongoDB 与关系型数据库对比:


MongoDB关系型数据库
亿级以上数据量轻松支持分库分表
灵活表结构轻松支持Entity Key/Value 表,关联查询比较痛苦
高并发读轻松支持需要优化
高并发写轻松支持需要优化
跨地区集群轻松支持需要定制方案
分片集群轻松支持需要中间件
地理位置查询比较完整的地理位置PG 还可以,其他数据库略麻烦
聚合计算功能很强大使用 Group By 等,能力有限
异构数据轻松支持使用 EKV 属性表
大宽表轻松支持性能受限

MongoDB 应用场景

从目前阿里云 MongoDB 云数据库上的用户看,MongoDB 的应用已经渗透到各个领域:

  • 游戏场景,使用 MongoDB 存储游戏用户信息,用户的装备、积分等直接以内嵌文档的形式存储,方便查询、更新;
  • 物流场景,使用 MongoDB 存储订单信息,订单状态在运送过程中会不断更新,以 MongoDB 内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来;
  • 社交场景,使用 MongoDB 存储存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能;
  • 物联网场景,使用 MongoDB 存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这些信息进行多维度的分析;
  • 视频直播,使用 MongoDB 存储用户信息、礼物信息等;
  • 大数据应用,使用云数据库 MongoDB 作为大数据的云存储系统,随时进行数据提取分析,掌握行业动态。

当前业务是否适合使用 MongoDB?

没有某个业务场景必须要使用 MongoDB 才能解决,但使用 MongoDB 通常能让你以更低的成本解决问题。如果你不清楚当前业务是否适合使用 MongoDB,可以通过做几道选择题来辅助决策。

应用特征Yes/No
应用不需要复杂/长事务及 join 支持必须 Yes
新应用,需求会变,数据模型无法确定,想快速迭代开发?
应用需要 2000-3000 以上的读写 QPS(更高也可以)?
应用需要 TB 甚至 PB 级别数据存储?
应用发展迅速,需要能快速水平扩展?
应用要求存储的数据不丢失?
应用需要 99.999% 高可用?
应用需要大量的地理位置查询、文本查询?

只要有一项需求满足就可以考虑使用 MongoDB,匹配越多,选择 MongoDB 越合适。

MongoDB 环境搭建

linux 安装 MongoDB

1)环境准备

linux系统:centos7
安装 MongoDB 社区版

# 查看linux版本
[root@hecs-403280 ~]# cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)

2)下载 MongoDB Community Server

下载地址:https://www.mongodb.com/try/download/community

image.png

# 下载MongoDB
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-6.0.5.tgz
tar -zxvf mongodb-linux-x86_64-rhel70-6.0.5.tgz

3)启动 MongoDB Server

# 创建dbpath和logpath
[root@hecs-403280 mongodb]# pwd
/usr/local/mongodb
[root@hecs-403280 mongodb]# mkdir -p data log
[root@hecs-403280 mongodb]# ls
bin  data  LICENSE-Community.txt  log  MPL-2  README  THIRD-PARTY-NOTICES

# 进入mongodb目录,启动mongodb服务
bin/mongod --port=27017 --dbpath=/usr/local/mongodb/data --logpath=/usr/local/mongodb/log/mongodb.log --bind_ip=0.0.0.0 --fork

–dbpath:指定数据文件存放目录
–logpath:指定日志文件,注意是指定文件不是目录
–logappend:使用追加的方式记录日志
–port:指定端口,默认为27017
–bind_ip:默认只监听localhost网卡
–fork:后台启动
–auth:开启认证模式

image.png

4)添加环境变量
修改/etc/profile,添加环境变量,方便执行 MongoDB 命令

export MONGODB_HOME=/usr/local/mongodb
PATH=$PATH:$MONGODB_HOME/bin   

然后执行 source /etc/profile 重新加载环境变量。

5)利用配置文件启动服务
编辑/usr/local/mongodb/conf/mongo.conf文件,内容如下:

systemLog:
  destination: file
  path: /usr/local/mongodb/log/mongod.log # log path
  logAppend: true
storage:
  dbPath: /usr/local/mongodb/data # data directory
  engine: wiredTiger  #存储引擎
  journal:            #是否启用journal日志
    enabled: true
net:
  bindIp: 0.0.0.0
  port: 27017 # port
processManagement:
  fork: true

注意:一定要yaml格式。
启动 mongod:

mongod -f /usr/local/mongodb/conf/mongo.conf

-f 选项表示将使用配置文件启动 mongodb。

6)关闭 MongoDB 服务
方式 1:

mongod --port=27017 --dbpath=/usr/local/mongodb/data --shutdown

方式 2:
进入 mongosh

use admin
# 关闭 MongoDB server 服务
db.shutdownServer()

mongosh 使用

mongosh 是 MongoDB 的交互式 JavaScript Shell 界面,它为系统管理员提供了强大的界面,并为开发人员提供了直接测试数据库查询和操作的方法。
注意:MongoDB 6.0 移除了mongo,使用 mongosh。

mongosh 下载地址:https://www.mongodb.com/try/download/shell

# centos7 安装mongosh
wget https://downloads.mongodb.com/compass/mongodb-mongosh-1.8.0.x86_64.rpm
yum install -y mongodb-mongosh-1.8.0.x86_64.rpm
# 连接mongodb server端
# mongosh --host=192.168.65.206 --port=27017 
# mongosh 192.168.65.206:27017
# 指定uri方式连接
# mongosh mongodb://192.168.65.206:27017/test
mongosh

–port:指定端口,默认为27017
–host:连接的主机地址,默认127.0.0.1

image.png

mongosh 常用命令

命令说明
show dbs | show databases显示数据库列表
use 数据库名切换数据库,如果不存在创建数据库
db.dropDatabase()删除数据库
show collections | show tables显示当前数据库的集合列表
db.集合名.stats()查看集合详情
db.集合名.drop()删除集合
show users显示当前数据库的用户列表
show roles显示当前数据库的角色列表
show profile显示最近发生的操作
load(“xxx.js”)执行一个 JavaScript 脚本文件
exit | quit退出当前 shell
help查看 mongodb 支持哪些命令
db.help()查询当前数据库支持的方法
db.集合名.help()显示集合的帮助信息
db.version()查看数据库版本

数据库操作

# 查看所有库
show dbs
# 切换到指定数据库,不存在则创建
use test
# 删除当前数据库  
db.dropDatabase()

集合操作

# 查看集合
show collections
# 创建集合
db.createCollection("emp")
# 删除集合
db.emp.drop()

创建集合语法

db.createCollection(name, options)

options 参数:

字段类型描述
capped布尔(可选)如果为 true,则创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。
size数值(可选)为固定集合指定一个最大值(以字节计)。
如果 capped 为 true,也需要指定该字段。
max数值(可选)指定固定集合中包含文档的最大数量。

注意:当集合不存在时,向集合中插入文档也会创建集合。

安全认证

使用用户名和密码来认证用户身份是 MongoDB 中最常用的安全认证方式。可以通过以下步骤实现:

  • 创建一个管理员用户(root)并设置密码,具有所有数据库的管理权限。
  • 创建一个或多个普通用户,指定相应的数据库和集合权限,并设置密码。

启用认证后,客户端连接 MongoDB 服务器时需要提供用户名和密码才能成功连接。

创建管理员用户

# 设置管理员用户名密码需要切换到admin库
use admin  
# 创建管理员
db.createUser({user:"firechou",pwd:"firechou",roles:["root"]})
# 查看当前数据库所有用户信息 
show users 
# 显示可设置权限
show roles 
# 显示所有用户
db.system.users.find()

image.png

常用权限

权限名描述
read允许用户读取指定数据库
readWrite允许用户读写指定数据库
dbAdmin允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问 system.profile
dbOwner允许用户在指定数据库中执行任意操作,增、删、改、查等
userAdmin允许用户向 system.users 集合写入,可以在指定数据库里创建、删除和管理用户
clusterAdmin只在 admin 数据库中可用,赋予用户所有分片和复制集相关函数的管理权限
readAnyDatabase只在 admin 数据库中可用,赋予用户所有数据库的读权限
readWriteAnyDatabase只在 admin 数据库中可用,赋予用户所有数据库的读写权限
userAdminAnyDatabase只在 admin 数据库中可用,赋予用户所有数据库的 userAdmin 权限
dbAdminAnyDatabase只在 admin 数据库中可用,赋予用户所有数据库的 dbAdmin 权限
root只在 admin 数据库中可用。超级账号,超级权限

重新赋予用户操作权限:

db.grantRolesToUser( "firechou" , [ 
    { role: "clusterAdmin", db: "admin" } ,
     { role: "userAdminAnyDatabase", db: "admin"},
     { role: "readWriteAnyDatabase", db: "admin"} 
 ])

删除用户:

db.dropUser("firechou")
# 删除当前数据库所有用户
db.dropAllUser()

用户认证,返回 1 表示认证成功:
image.png

创建应用数据库用户

use appdb
db.createUser({user:"appdb",pwd:"firechou",roles:["dbOwner"]})

MongoDB 启用鉴权

默认情况下,MongoDB 不会启用鉴权,以鉴权模式启动 MongoDB:

mongod -f /usr/local/mongodb/conf/mongo.conf --auth

启用鉴权之后,连接 MongoDB 的相关操作都需要提供身份认证。

mongosh 192.168.65.206:27017 -u firechou -p firechou --authenticationDatabase=admin

Docker 安装 MongoDB

https://hub.docker.com/_/mongo?tab=description&page=3

# 拉取mongo镜像
docker pull mongo:6.0.5
# 运行mongo镜像
docker run --name mongo-server -p 29017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=firechou \
-e MONGO_INITDB_ROOT_PASSWORD=firechou \
-d mongo:6.0.5 --wiredTigerCacheSizeGB 1

默认情况下,Mongo 会将 wiredTigerCacheSizeGB 设置为与主机总内存成比例的值,而不考虑你可能对容器施加的内存限制。
MONGO_INITDB_ROOT_USERNAME 和 MONGO_INITDB_ROOT_PASSWORD 都存在就会启用身份认证(mongod --auth)
利用 mongosh 建立连接:

# 远程连接
mongosh ip:29017 -u firechou -p firechou

MongoDB 常用工具

GUI 工具

(1)官方GUI:COMPASS
MongoDB 图形化管理工具(GUI),能够帮助您在不需要知道 MongoDB 查询语法的前提下,便利地分析和理解您的数据库模式,并且帮助您可视化地构建查询。

下载地址:https://www.mongodb.com/zh-cn/products/compass

image.png

(2)Robo 3T(免费)

下载地址:https://robomongo.org/

(3)Studio 3T(收费,试用30天)

下载地址:https://studio3t.com/download/

MongoDB Database Tools

下载地址:https://www.mongodb.com/try/download/database-tools

文件名称作用
mongostat数据库性能监控工具
mongotop热点表监控工具
mongodump数据库逻辑备份工具
mongorestore数据库逻辑恢复工具
mongoexport数据导出工具
mongoimport数据导入工具
bsondumpBSON 格式转换工具
mongofilesGridFS 文件工具

MongoDB 文档操作

SQL to MongoDB Mapping Chart :https://www.mongodb.com/docs/manual/reference/sql-comparison/

插入文档

MongoDB 提供了以下方法将文档插入到集合中:

  • db.collection.insertOne ():将单个文档插入到集合中。
  • db.collection.insertMany ():将多个文档插入到集合中。

新增单个文档

  • insertOne:用于向集合中插入一条文档数据,支持 writeConcern。语法如下:
db.collection.insertOne(
   <document>,
   {
      writeConcern: <document>
   }
)

image.png
设置 writeConcern 参数的示例:

db.emps.insertOne(
   { name: "firechou", age: 33},
   {
      writeConcern: { w: "majority", j: true, wtimeout: 5000 }
   }
)

image.png
writeConcern 是 MongoDB 中用来控制写入确认的选项。以下是 writeConcern 参数的一些常见选项:

w:指定写入确认级别。如果指定为数字,则表示要等待写入操作完成的节点数。如果指定为 majority,则表示等待大多数节点完成写入操作。默认为 1,表示等待写入操作完成的节点数为 1。
j:表示写入操作是否要求持久化到磁盘。如果设置为 true,则表示写入操作必须持久化到磁盘后才返回成功。如果设置为 false,则表示写入操作可能在数据被持久化到磁盘之前返回成功。默认为 false。
wtimeout:表示等待写入操作完成的超时时间,单位为毫秒。如果超过指定的时间仍然没有返回确认信息,则返回错误。默认为 0,表示不设置超时时间。

批量新增文档

  • insertMany:向指定集合中插入多条文档数据
db.collection.insertMany(
   [ <document 1> , <document 2>, ... ],
   {
      writeConcern: <document>,
      ordered: <boolean>      
   }
)

writeConcern:写入确认选项,可选。
ordered:指定是否按顺序写入,默认 true,按顺序写入。

db.emps.insertMany([{x:1},{y:5}])

image.png

测试:批量插入 50 条随机数据
编辑脚本 book.js:

var tags = ["nosql","mongodb","document","developer","popular"];
var types = ["technology","sociality","travel","novel","literature"];
var books=[];
for(var i=0;i<50;i++){
    var typeIdx = Math.floor(Math.random()*types.length);
    var tagIdx = Math.floor(Math.random()*tags.length);
    var favCount = Math.floor(Math.random()*100);
    var book = {
        title: "book-"+i,
        type: types[typeIdx],
        tag: tags[tagIdx],
        favCount: favCount,
        author: "xxx"+i
    };
    books.push(book)
}
db.books.insertMany(books);

进入 mongosh,执行:

load("books.js")

image.png

查询文档

查询集合中的若干文档
语法格式如下:

db.collection.find(query, projection)

query:可选,使用查询操作符指定查询条件
projection:可选,使用投影操作符指定返回的键。查询时返回文档中所有键值,只需省略该参数即可(默认省略)。投影时,_id 为 1 的时候,其他字段必须是 1;_id 是 0 的时候,其他字段可以是 0;如果没有 _id 字段约束,多个其他字段必须同为 0 或同为 1。

如果查询返回的条目数量较多,mongosh 则会自动实现分批显示。默认情况下每次只显示 20 条,可以输入 it 命令读取下一批。
image.png

查询集合中的第一个文档

语法格式如下:

db.collection.findOne(query, projection)

示例:

db.books.findOne()
db.books.find({tag:"nosql"},{title:1,author:1})

image.png
如果你需要以易读的方式来读取数据,可以使用 pretty 方法,语法格式如下:

db.collection.find().pretty()

注意:pretty() 方法以格式化的方式来显示所有文档。

条件查询

查询条件对照表:

**SQL **MQL
a = 1{a: 1}
a <> 1{a: {$ne: 1}}
a > 1{a: {$gt: 1}}
a >= 1{a: {$gte: 1}}
a < 1{a: {$lt: 1}}
a <= 1{a: {$lte: 1}}

查询逻辑对照表:

**SQL **MQL
a = 1 AND b = 1{a: 1, b: 1}或{$and: [{a: 1}, {b: 1}]}
a = 1 OR b = 1{$or: [{a: 1}, {b: 1}]}
a IS NULL{a: {$exists: false}}
a IN (1, 2, 3){a: {$in: [1, 2, 3]}}

查询逻辑运算符:

$lt: 存在并小于
$lte: 存在并小于等于
$gt: 存在并大于
$gte: 存在并大于等于
$ne: 不存在或存在但不等于
$in: 存在并在指定数组中
$nin: 不存在或不在指定数组中
$or: 匹配两个或多个条件中的一个
$and: 匹配全部条件

# 查询带有nosql标签的book文档:
db.books.find({tag:"nosql"})
# 按照id查询单个book文档:
db.books.find({_id:ObjectId("6596c598e226cbe365ee4796")})
# 查询分类为“travel”、收藏数超过60个的book文档:
db.books.find({type:"travel",favCount:{$gt:60}})

正则表达式匹配查询

MongoDB 使用 $regex 操作符来设置匹配字符串的正则表达式。

# 使用正则表达式查找type包含 so 字符串的book
db.books.find({type:{$regex:"so"}})
# 或者
db.books.find({type:/so/})

排序

在 MongoDB 中使用 sort() 方法对数据进行排序

# 指定按收藏数(favCount)降序返回
db.books.find({type:"travel"}).sort({favCount:-1})

1 为升序排列,而 -1 是用于降序排列

image.png

分页

skip 用于指定跳过记录数,limit 则用于限定返回结果数量。可以在执行 find 命令的同时指定 skip、limit 参数,以此实现分页的功能。
比如,假定每页大小为 8 条,查询第 3 页的 book 文档:

db.books.find().skip(16).limit(8)

.skip(16) 表示跳过前面 16 条记录,即前两页的所有记录。
.limit(8) 表示返回 8 条记录,即第三页的所有记录。

(1)处理分页问题-巧分页
数据量大的时候,应该避免使用 skip/limit 形式的分页。
替代方案:使用查询条件+唯一排序条件。
例如:

# 第一页
db.books.find({}).sort({_id: 1}).limit(10); 
# 第二页
db.books.find({_id: {$gt: <第一页最后一个_id>}}).sort({_id: 1}).limit(10); 
# 第三页
db.books.find({_id: {$gt: <第二页最后一个_id>}}).sort({_id: 1}).limit(10);

(2)处理分页问题–避免使用 count
尽可能不要计算总页数,特别是数据量大和查询条件不能完整命中索引时。
考虑以下场景:假设集合总共有 1000w 条数据,在没有索引的情况下考虑以下查询:

db.coll.find({x: 100}).limit(50);
db.coll.count({x: 100}); 

前者只需要遍历前 n 条,直到找到 50 条 x=100 的文档即可结束;
后者需要遍历完 1000w 条找到所有符合要求的文档才能得到结果。为了计算总页数而进行的 count() 往往是拖慢页面整体加载速度的原因;

更新文档

MongoDB 提供了以下方法来更新集合中的文档:

  • db.collection.updateOne ()

即使多个文档可能与指定的筛选器匹配,也只会更新第一个匹配的文档。

  • db.collection.updateMany ()

更新与指定筛选器匹配的所有文档。

更新操作符:

操作符格式描述
$set{$set:{field:value}}指定一个键并更新值,若键不存在则创建
$unset{$unset : {field : 1 }}删除一个键
$inc{$inc : {field : value } }对数值类型进行增减
$rename{$rename : {old_field_name : new_field_name } }修改字段名称
$push{ $push : {field : value } }将数值追加到数组中,若数组不存在则会进行初始化
$pushAll{$pushAll : {field : value_array }}追加多个值到一个数组字段内
$pull{$pull : {field : _value } }从数组中删除指定的元素
$addToSet{$addToSet : {field : value } }添加元素到数组中,具有排重功能
$pop{$pop : {field : 1 }}删除数组的第一个或最后一个元素

更新单个文档

updateOne 语法如下:

db.collection.updateOne(
   <filter>,
   <update>,
   {
     upsert: <boolean>,
     writeConcern: <document>,
     collation: <document>,
     arrayFilters: [ <filterdocument1>, ... ],
     hint:  <document|string>        // Available starting in MongoDB 4.2.1
   }
)

db.collection.updateOne() 方法的参数含义如下:

:一个筛选器对象,用于指定要更新的文档。只有与筛选器对象匹配的第一个文档才会被更新。
:一个更新操作对象,用于指定如何更新文档。可以使用一些操作符,例如 s e t 、 set、 setinc、 u n s e t 等,以更新文档中的特定字段。 u p s e r t :一个布尔值,用于指定如果找不到与筛选器匹配的文档时是否应插入一个新文档。如果 u p s e r t 为 t r u e ,则会插入一个新文档。默认值为 f a l s e 。 w r i t e C o n c e r n :一个文档,用于指定写入操作的安全级别。可以指定写入操作需要到达的节点数或等待写入操作的时间。 c o l l a t i o n :一个文档,用于指定用于查询的排序规则。例如,可以通过指定 l o c a l e 属性来指定语言环境,从而实现基于区域设置的排序。 a r r a y F i l t e r s :一个数组,用于指定要更新的数组元素。数组元素是通过使用更新操作符 unset 等,以更新文档中的特定字段。 upsert:一个布尔值,用于指定如果找不到与筛选器匹配的文档时是否应插入一个新文档。如果 upsert 为 true,则会插入一个新文档。默认值为 false。 writeConcern:一个文档,用于指定写入操作的安全级别。可以指定写入操作需要到达的节点数或等待写入操作的时间。 collation:一个文档,用于指定用于查询的排序规则。例如,可以通过指定 locale 属性来指定语言环境,从而实现基于区域设置的排序。 arrayFilters:一个数组,用于指定要更新的数组元素。数组元素是通过使用更新操作符 unset等,以更新文档中的特定字段。upsert:一个布尔值,用于指定如果找不到与筛选器匹配的文档时是否应插入一个新文档。如果upserttrue,则会插入一个新文档。默认值为falsewriteConcern:一个文档,用于指定写入操作的安全级别。可以指定写入操作需要到达的节点数或等待写入操作的时间。collation:一个文档,用于指定用于查询的排序规则。例如,可以通过指定locale属性来指定语言环境,从而实现基于区域设置的排序。arrayFilters:一个数组,用于指定要更新的数组元素。数组元素是通过使用更新操作符[]和$来指定的。
hint:一个文档或字符串,用于指定查询使用的索引。该参数仅在 MongoDB 4.2.1 及以上版本中可用。
注意,除了 filter 和 update 参数外,其他参数都是可选的。

某个 book 文档被收藏了,则需要将该文档的 favCount 字段自增:

db.books.updateOne({_id:ObjectId("6596c598e226cbe365ee47ac")},{$inc:{favCount:1}})

image.png
upsert 是一种特殊的更新,其表现为如果目标文档不存在,则执行插入命令。

db.books.updateOne(
    {title:"my book"},
    {$set:{tags:["nosql","mongodb"],type:"none",author:"firechou"}},
    {upsert:true}
)

更新多个文档

updateMany 更新与集合的指定筛选器匹配的所有文档.
将分类为“novel”的文档的增加发布时间(publishedDate):

db.books.updateMany({type:"novel"},{$set:{publishedDate:new Date()}})

(1)findAndModify
findAndModify 兼容了查询和修改指定文档的功能,findAndModify 只能更新单个文档:

# 将某个book文档的收藏数(favCount)加1
db.books.findAndModify({
    query:{_id:ObjectId("6457a39c817728350ec83b9d")},
    update:{$inc:{favCount:1}}
})

该操作会返回符合查询条件的文档数据,并完成对文档的修改。
默认情况下,findAndModify 会返回修改前的“旧”数据。如果希望返回修改后的数据,则可以指定 new 选项:

db.books.findAndModify({
    query:{_id:ObjectId("6457a39c817728350ec83b9d")},
    update:{$inc:{favCount:1}},
    new: true
})

与 findAndModify 语义相近的命令如下:

  • findOneAndUpdate:更新单个文档并返回更新前(或更新后)的文档。
  • findOneAndReplace:替换单个文档并返回替换前(或替换后)的文档。

删除文档

deleteOne & deleteMany

官方推荐使用 deleteOne() 和 deleteMany() 方法删除文档,语法格式如下:

# 删除 type 等于 novel 的一个文档
db.books.deleteOne({ type:"novel" })
# 删除集合下全部文档
db.books.deleteMany({})
# 删除 type等于 novel 的全部文档
db.books.deleteMany({ type:"novel" })

注意:remove、deleteMany 命令需要对查询范围内的文档逐个删除,如果希望删除整个集合,则使用 drop 命令会更加高效。

findOneAndDelete

deleteOne 命令在删除文档后只会返回确认性的信息,如果希望获得被删除的文档,则可以使用 findOneAndDelete 命令:

db.books.findOneAndDelete({type:"novel"})

除了在结果中返回删除文档,findOneAndDelete 命令还允许定义“删除的顺序”,即按照指定顺序删除找到的第一个文档。利用这个特性,findOneAndDelete 可以实现队列的先进先出:

db.books.findOneAndDelete({type:"novel"},{sort:{favCount:1}})

批量操作

bulkwrite() 方法提供了执行批量插入、更新和删除操作的能力。
bulkWrite() 支持以下写操作:

  • insertOne
  • updateOne
  • updateMany
  • replaceOne
  • deleteOne
  • deleteMany

每个写操作都作为数组中的文档传递给 bulkWrite()。

db.pizzas.insertMany( [
   { _id: 0, type: "pepperoni", size: "small", price: 4 },
   { _id: 1, type: "cheese", size: "medium", price: 7 },
   { _id: 2, type: "vegan", size: "large", price: 8 }
] )

db.pizzas.bulkWrite( [
      { insertOne: { document: { _id: 3, type: "beef", size: "medium", price: 6 } } },
      { insertOne: { document: { _id: 4, type: "sausage", size: "large", price: 10 } } },
      { updateOne: {
         filter: { type: "cheese" },
         update: { $set: { price: 8 } }
      } },
      { deleteOne: { filter: { type: "pepperoni"} } },
      { replaceOne: {
         filter: { type: "vegan" },
         replacement: { type: "tofu", size: "small", price: 4 }
      } }
   ] )

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/308928.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

构建安全可靠的系统:第二十一章到附录 A

第二十一章&#xff1a;建立安全和可靠性文化 原文&#xff1a;21. Building a Culture of Security and Reliability 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 作者&#xff1a;Heather Adkins 与 Peter Valchev&#xff0c;Felix Grbert&#xff0c;Ana Oprea…

计算机体系结构----重排序缓冲(ROB)

ROB的思想&#xff1a;不按顺序完成指令&#xff0c;但在使结果对体系结构状态可见之前重新排序 当指令被解码时&#xff0c;它会在 ROB 中保留下一个顺序条目当指令完成时&#xff0c;它将结果写入 ROB 条目当指令在 ROB 中最早并且无一例外地完成时&#xff0c;其结果移动到…

Java-布隆过滤器的实现

文章目录 前言一、概述二、误差率三、hash 函数的选择四、手写布隆过滤器五、guava 中的布隆过滤器 前言 如果想要判断一个元素是不是在一个集合里&#xff0c;一般想到的是将所有元素保存起来&#xff0c;然后通过比较确定。链表&#xff0c;树等等数据结构都是这种思路&…

LeetCode 145. 二叉树的后序遍历

145. 二叉树的后序遍历 给你一棵二叉树的根节点 root &#xff0c;返回其节点值的 后序遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[3,2,1]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; 输入&…

Vue3:vue-cli项目创建及vue.config.js配置

一、node.js检测或安装&#xff1a; node -v node.js官方 二、vue-cli安装&#xff1a; npm install -g vue/cli # OR yarn global add vue/cli/*如果安装的时候报错&#xff0c;可以尝试一下方法 删除C:\Users**\AppData\Roaming下的npm和npm-cache文件夹 删除项目下的node…

C语言基础语法跟练 day2

题源&#xff1a;牛客网 16、BoBo写了一个十六进制整数ABCDEF&#xff0c;他问KiKi对应的十进制整数是多少。 #include <stdio.h>int main() { //创建变量char arr[] "ABCDEF";int i;int sum0,c; //依次转换十六进制为十进制for(i0; arr[i]!\0; i){char b …

每日学习更新(LQR+iLQR)

一直想更新一下根据cost to go来推导LQR&#xff0c;之前的话可能会直接套问题&#xff0c;但是对于理论有些困惑&#xff0c;正好最近在学习ilqr轨迹生成/优化&#xff0c;因此来推一下公式&#xff0c;以下参考B站Dr_CAN&#xff0c;链接如下&#xff1a; 【最优控制】5_线性…

记录汇川:H5U与Fctory IO测试6

主程序&#xff1a; 子程序: IO映射 子程序&#xff1a; 辅助上料 子程序&#xff1a; 自动程序 Fctory IO配置&#xff1a; 实际动作如下&#xff1a; Fctory IO测试6

软件测试工具Robot Framework如何安装

安装文件准备 表1 安装文件准备 Robot框架结构 为了更好的了解环境安装&#xff0c;我们先看下框架结构&#xff1a; 图1 Robot Framework Architecture Robot Framework 通过导入不同的库&#xff0c;就可以使用库中所提供的关键字&#xff0c;从而时行相关的测试。有几个标…

2023年全国职业院校技能大赛(高职组)“云计算应用”赛项赛卷②

2023年全国职业院校技能大赛&#xff08;高职组&#xff09; “云计算应用”赛项赛卷2 目录 需要竞赛软件包环境以及备赛资源可私信博主&#xff01;&#xff01;&#xff01; 2023年全国职业院校技能大赛&#xff08;高职组&#xff09; “云计算应用”赛项赛卷2 模块一 …

大众汽车宣布将ChatGPT,批量集成在多种汽车中!

1月9日&#xff0c;大众汽车在官网宣布&#xff0c;将ChatGPT批量集成到电动、内燃机汽车中。 大众表示&#xff0c;将ChatGPT与其IDA语音助手相结合&#xff0c;用户通过自然语言就能与ChatGPT进行互动&#xff0c;例如&#xff0c;帮我看看最近的三星米其林饭店在哪里&#…

Redis系列-15.Redis的IO多路复用原理解析

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码、Kafka原理、分布式技术原理、数据库技术&#x1f525;如果感觉博主的文章还不错的…

Java顺序表(1)

&#x1f435;本篇文章将对顺序表中的方法进行模拟实现 一、线性表 线性表是指在逻辑结构上呈连续的线性结构&#xff0c;而在物理结构上不一定是连续的结构&#xff0c;常见的线性表有&#xff1a;顺序表、链表、栈、队列等 二、顺序表 顺序表一般采用数组来存储数据&#x…

ELF文件格式解析二

使用objdump命令查看elf文件 objdump -x 查看elf文件所有头部的信息 所有的elf文件。 程序头部&#xff08;Program Header&#xff09;中&#xff0c;都以 PT_PHDR和PT_INTERP先开始。这两个段必须在所有可加载段项目的前面。 从上图中的INTERP段中&#xff0c;可以看到改段…

Android App打包加固后的APK无法安装问题

最近开发的一个应用要上架&#xff0c;正常流程打完包后去加固&#xff0c;由于以前一直用的是360的加固助手&#xff0c;这里开始也是选择用它。 使用360加固&#xff1a; 问题一、开始出现的问题是说应用未签名无法加固&#xff0c;我明明是签名后打的包&#xff0c;怎么会…

十分钟部署清华 ChatGLM-6B,实测效果超预期(Linux版)

前段时间&#xff0c;清华公布了中英双语对话模型 ChatGLM-6B&#xff0c;具有60亿的参数&#xff0c;初具问答和对话功能。 最&#xff01;最&#xff01;最重要的是它能够支持私有化部署&#xff0c;大部分实验室的服务器基本上都能跑起来。因为条件特殊&#xff0c;实验室网…

介绍几种常见的质数筛选法

质数筛选法 1.暴力筛选法 :smirk:2.普通优化 :rofl:3.埃氏筛法:cold_sweat:4.线性筛选法:scream: 质数&#xff1a;除了1和他本身没有其它因数的正整数就是质数。1不是质数&#xff0c;2是质数。 1.暴力筛选法 &#x1f60f; 原理 求x的质数&#xff0c;令y从2到 x \sqrt[]{x…

资源素材网站源码,功能齐备,界面干净整洁,附带安装教程

搭建教程 简单安装说明&#xff1a; 1、整站程序上传后台 2、然后导入数据库文件到数据库&#xff0c; 3、修改conf里面的conf的数据库名字及密码 4、配置伪静态 规则&#xff1a; location ~* \.(htm)$ { rewrite "^(.*)/(.?).htm(.*?)$" $1/index.php?$2…

Docker安装Jenkins,配置Maven和Java

前言 这是一个java的springboot项目&#xff0c;使用maven构建 安装准备 需要将maven和jdk安装在服务器上&#xff0c;Jenkins需要用到&#xff0c;还有创建一个jenkins的目录&#xff0c;安装命令如下&#xff1a; docker run -d -uroot -p 9095:8080 -p 50000:50000 --n…

20240109适配selinux让移远的4G模块EC20在Firefly的AIO-3399J开发板的Android11下跑通

20240109适配selinux让移远的4G模块EC20在Firefly的AIO-3399J开发板的Android11下跑通 2024/1/9 10:46 缘起&#xff1a;使用友善之臂的Android11可以让EC20上网&#xff0c;但是同样的修改步骤&#xff0c;Toybrick的Android11不能让EC20上网。 最后确认是selinux的问题&#…