1. database
在 MongoDB 中,数据库保存一个或多个文档集合。
等价于关系型数据库中的database
// 选中数据库
use 数据库名
如果数据库不存在,MongoDB 会在首次为该数据库存储数据时自动创建该数据库
1.1 命名规范
- 数据库名称区分大小写:
数据库名称在 MongoDB 中区分大小写。它们还有一个额外的限制,大小写不能是数据库名称之间的唯一区别 - 对于在 Windows系统 上运行的 MongoDB 服务,数据库名称不能包含以下任何字符, 同时也不能包含空字符
/\. "$*<>:|?
- 对于在 Unix 和 Linux 系统上运行的 MongoDB 服务,数据库名称不能包含以下任何字符
/\. "$
- 数据库名称不能为空且必须少于 64 个字符
2. collection
MongoDB 将文档(document)存储在集合(collection)中。集合类似于关系数据库中的表
2.1 命名规范
- 集合名称应以下划线或字母字符开头,并且不能:
包含 $
空字符串
system. 前缀(仅供内部使用)
如果集合名称包含特殊字符,例如下划线字符,或 以数字开头,则要访问集合,使用 mongosh 中的 db.getCollection() 方法或 驱动程序的类似方法 .
- 命名空间长度
当featureCompatibilityVersion
设置为4.4 及之后版本,. 的总长度(包括了 .
)不能超过255 字节,
当featureCompatibilityVersion
设置为4.2及之前版本,总长度不能超过120字节
2.2 创建collection
- 隐式创建:
当给一个不存在的集合插入文档或创建索引时,此时系统会自动创建一个对应的集合 - 显示创建
MongoDB 提供db.createCollection()
方法来显式创建具有各种选项的集合,例如设置最大大小或文档验证规则。如果您没有指定这些选项,则不需要显式创建集合
2.3 文档验证
默认情况下,集合不要求其文档具有相同的模式;即单个集合中的文档不需要具有相同的字段集,并且字段的数据类型可以在集合中的文档之间有所不同。 从mongodb 3.2 版本开始,可以在更新和插入操作期间对集合强制执行文档验证规则,参考:https://www.mongodb.com/docs/manual/core/schema-validation/
2.4 唯一标识符(unique Identifiers)
在 3.6 版本新增, 集合被分配了一个不可变的 UUID。集合 UUID 在副本集的所有成员和分片集群中的分片中保持相同。 可以理解为,UUID 是集合在副本集或者集群中的唯一身份标识
在 mongosh 工具中 通过方法db.getCollectionInfos()
查看
2.5 固定集合(capped collection)
定义:
固定集合是一种特殊类型的集合,可以声明集合的容量大小,其行为类似于循环队列,数据插入时新文档插入到队列的末尾,如果队列已经满了,旧文档就会被新文档插入覆盖。 固定文档的写入速度快,文档数据被顺序写入磁盘的固定空间(不建立索引)应用场景:
固定集合适用于任何想要自动淘汰过期属性的场景,比如日志文件,聊天记录,通话信息记录等只需保留最近某段时间内的应用场景,都会使用到MongoDB的固定集合。-
操作指令
1.创建
不同于普通集合,固定集合必须在使用前显式创建,可以调用db.createCollection()
方法调用
创建示例:// 创建 名为capped 的固定集合,集合的容量为(size):10000byte db.createCollection("capped",{capped:true,size:10000}) // 创建 名为capped1 的固定集合,集合的容量为(size): 10000byte,同时指定了集合最多的文档数为1000条 db.createCollection("capped1",{capped:true,size:10000,max:1000})
注意:
size
参数是创建固定集合的必选参数,并且生效的优先级高于max
参数。如果 size 字段小于或等于 4096,则集合的上限为 4096 字节。否则,MongoDB 将提高提供的大小以使其成为 256 的整数倍- 判断是否为固定集合
// 语法名:db.collection名.isCapped() // 判断 名叫capped1的集合是否是固定集合 db.collection.isCapped()
- 查询
如果在未指定排序的固定集合上执行find()
,则 MongoDB 保证结果的排序与插入顺序相同。 要以反向插入顺序检索文档,请发出 find() 以及将$natural
参数设置为 -1 的sort()
方法
示例
db.cappedCollection.find().sort( { $natural: -1 } )
-
特性
- 文档是按照顺序插入的,查询不需要索引即可按插入顺序返回文档。从而提高了固定集合的插入吞吐量。
- 当插入的文档超过固定集合的容量上限,会自动删除最旧的文档来给新的文档插入
- 固定集合默认有 _id 字段和 _id 字段上的索引
-
限制和建议
- 从 MongoDB 5.0 开始,在从固定集合中读取数据时,不能设置
read concern
为snapshot
- 如果您计划更新固定集合中的文档,请创建索引,以便这些更新操作不需要全文档扫描
- 从 mongoddb 3.2 版本开始,无法修改或者替换固定集合中文档的大小
- 不能从固定集合中删除文档。要从集合中删除所有文档,请使用
drop()
方法删除集合并重新创建集合 - 不支持分片技术
- 从 MongoDB 4.2 版本开始,不支持在事务中写入固定集合
- 不支持 Stable API V1
- 聚合管道
$out
无法将结果写入固定集合
- 从 MongoDB 5.0 开始,在从固定集合中读取数据时,不能设置
2.6 时间序列集合(time series collection)
与普通集合相比,在时间序列集合中存储时间序列数据可以提高查询效率,并减少数据和索引的磁盘使用
参考: https://www.jianshu.com/p/52c60e665b9d
3 view
MongoDB 视图是一个可查询对象,其内容由其他集合或视图上的聚合管道定义。 MongoDB 不会将视图内容保存到磁盘。当客户端查询视图时,系统才会计算返回结果。 MongoDB 可以要求客户端具有查询视图的权限。 MongoDB 不支持针对视图的写操作
3.1 创建 view
方法一:
使用mongosh 中的db.createCollection()
方法:
该方法既支持collection 的创建 同时也支持view 的创建
db.createCollection(
"",
{
"viewOn" : "
方法二:
使用mongosh 中的db.createView()
方法:
db.createView(
"",
"
注意:必须在与源集合相同的数据库中创建视图
示例:
创建学生集合
db.students.insertMany( [
{ sID: 22001, name: "Alex", year: 1, score: 4.0 },
{ sID: 21001, name: "bernie", year: 2, score: 3.7 },
{ sID: 20010, name: "Chris", year: 3, score: 2.5 },
{ sID: 22021, name: "Drew", year: 1, score: 3.2 },
{ sID: 17301, name: "harley", year: 6, score: 3.1 },
{ sID: 21022, name: "Farmer", year: 1, score: 2.2 },
{ sID: 20020, name: "george", year: 3, score: 2.8 },
{ sID: 18020, name: "Harley", year: 5, score: 2.8 },
] )
``
使用 db.createView()
创建仅限于一年级学生的视图:
db.createView(
"firstYears",
"students",
[ { $match: { year: 1 } } ]
)
db.createCollection()
方法允许您创建具有特定选项的集合或视图。 下面的示例创建一个graduateStudents 视图。该视图仅包含 $match
阶段选择的文档。可选的排序规则设置确定排序顺序
db.createCollection(
"graduateStudents",
{
viewOn: "students",
pipeline: [ { $match: { $expr: { $gt: [ "$year", 4 ] } } } ],
collation: { locale: "en", caseFirst: "upper" }
}
)
3.2 特性
- 只读权限:
视图是只支持读操作;视图上的写操作会报错,视图支持如下的读操作方法
db.collection.find()
db.collection.findOne()
db.collection.aggregate()
db.collection.countDocuments()
db.collection.estimatedDocumentCount()
db.collection.count()
db.collection.distinct()
- 索引使用和排序操作
- 视图可以使用底层的集合的索引
- 由于索引位于基础集合上,因此您无法直接在视图上创建、删除或重新构建索引,也无法获取视图上的索引列表
- 从 MongoDB 4.4 开始,您可以在视图上运行 find 命令时指定
$natural
排序。 MongoDB 的早期版本不支持对视图进行$natural
排序 - 视图的底层聚合管道受限于 100 兆字节的内存限制,用于阻塞排序和阻塞组操作。从 MongoDB 4.4 开始,您可以在视图上发出带有 allowDiskUse: true 的 find 命令,以允许 MongoDB 使用临时文件来阻止排序和分组操作。
- 规则限制
视图上的 find() 操作不支持以下运算符:
$
$elemMatch
$slice
$meta
视图名不可变:
视图的名称不能重命名分片视图
如果视图的底层集合是分片的,则视图被认为是分片的。因此,您不能为$lookup
和$graphLookup
操作中的 from 字段指定分片视图。-
视图和排序规则(collection)
- 视图在创建时可以设定排序规则,如果未指定排序规则,则视图的默认排序规则是“simple”二进制比较排序规则。即视图不继承集合的默认排序规则
- 视图上的字符串比较使用视图的默认排序规则。尝试更改或覆盖视图的默认排序规则的操作将失败并出现错误
- 如果从另一个视图创建视图,则不能指定与源视图的排序规则不同的排序规则
- 如果执行涉及多个视图的聚合,例如使用 graphLookup,则视图必须具有相同的排序规则
-
使用视图连接两个集合:
view 和lookup
操作符组合使用可以实现两个集合的关联查询
示例:
数据构造:db.inventory.insertMany( [ { prodId: 100, price: 20, quantity: 125 }, { prodId: 101, price: 10, quantity: 234 }, { prodId: 102, price: 15, quantity: 432 }, { prodId: 103, price: 17, quantity: 320 } ] ) db.orders.insertMany( [ { orderID: 201, custid: 301, prodId: 100, numPurchased: 20 }, { orderID: 202, custid: 302, prodId: 101, numPurchased: 10 }, { orderID: 203, custid: 303, prodId: 102, numPurchased: 5 }, { orderID: 204, custid: 303, prodId: 103, numPurchased: 15 }, { orderID: 205, custid: 303, prodId: 103, numPurchased: 20 }, { orderID: 206, custid: 302, prodId: 102, numPurchased: 1 }, { orderID: 207, custid: 302, prodId: 101, numPurchased: 5 }, { orderID: 208, custid: 301, prodId: 100, numPurchased: 10 }, { orderID: 209, custid: 303, prodId: 103, numPurchased: 30 } ] )
关联查询构造视图
db.createView( "sales", "orders", [ { $lookup: { from: "inventory", localField: "prodId", foreignField: "prodId", as: "inventoryDocs" } }, { $project: { _id: 0, prodId: 1, orderId: 1, numPurchased: 1, price: "$inventoryDocs.price" } }, { $unwind: "$price" } ] )
- 通过db.createView()创建了一个名叫sales 的视图
- sales视图基于orders集合
-
$lookup
操作符使用orders集合中的 prodId 字段来关联inventory集合 prodId 字段的文档 - 匹配的文档作为数组添加到 inventoryDocs 字段中
-
$project
操作符选择需要字段的子集 -
$unwind
操作符将$inventoryDocs.price
字段从数组转换为标量值
获取视图的数据
$ db.sales.find() [ { prodId: 100, numPurchased: 20, price: 20 }, { prodId: 101, numPurchased: 10, price: 10 }, { prodId: 102, numPurchased: 5, price: 15 }, { prodId: 103, numPurchased: 15, price: 17 }, { prodId: 103, numPurchased: 20, price: 17 }, { prodId: 102, numPurchased: 1, price: 15 }, { prodId: 101, numPurchased: 5, price: 10 }, { prodId: 100, numPurchased: 10, price: 20 }, { prodId: 103, numPurchased: 30, price: 17 } ]