MongoDB | 基础学习笔记
Contents
目录
特性
- 索引(indexing)
MongoDB支持通用二级索引,允许多种快速查询,且提供唯一索引、复合索引、地理空间索引以及全文索引
- 聚合(aggregation)
MongoDB支持 “聚合管道(aggregation pipeline)”。用户能通过简单的片段创建复杂的聚合,并通过数据库自动优化。
- 特殊的集合类型
MongoDB支持存在时间有限的集合,适用于那些将在某个时刻过期的数据,如会话(session)。类似的,MongoDB也支持固定大小的集合,用于保存近期数据,如日志。
- 文件存储
MongoDB支持一种非常易用的协议,用于存储大文件和文件元数据。
- 与关系型数据库区别
不具备 连接(join)
和 复杂的 多行事务(multirow transaction)
基础
基本概念
- 文档
文档是MongoDB中数据的基本单元,非常类似于关系型数据库管理系统中的行,但更具表现力, 表现力。
- 集合
类似地,集合(collection)可以看作是一个拥有动态模式(dynamic schema)的表。
- 数据库
MongoDB的一个实例可以拥有多个相互独立的数据库(database),每一个数据库都拥有自己的集合。
- 特殊键
每一个文档都有一个特殊的键”_id”, 这个键在文档所属的集合中是唯一的。
- Shell
MongoDB自带了一个简单但功能强大的JavaScript shell,可用于管理MongoDB的实例或数据操作。
文档
文档就是键值对的一个有序集。
Note: - 文档的键是字符串, 除了少数例外情况,键可以使用任意UTF-8字符。 - 键不能含有\0(空字符)。这个字符用于表示键的结尾。 - .和$具有特殊意义,只能在特定环境下使用 - MongoDB不但区分类型,而且区分大小写 - MongoDB的文档不能有重复的键。
集合
集合就是一组文档。如果将MongoDB中的一个文档比喻为关系型数据库中的一行,那么一个集合就相当于一张表。
动态模式
集合是动态模式的。即一个集合里面的文档可是是各式各样的。例如,下面两个文档可以存储在同一个集合里面:
|
|
Note:
- 推荐模式:将相关类型的文档组织在一起(一个集合只存放一种类型的文档,这样可有效的建立索引)
命名
集合使用名称进行标识。集合名可以是满足下列条件的任意UTF-8字符串。
- 集合名不能是空字符串(”“)
- 集合名不能包含\0字符(空字符),这个字符表示集合名的结束。
- 集合名不能以“system.”开头,这是为系统集合保留的前缀。例如,system.users这个集合保存着数据库的用户信息,而system.namespaces集合保存着所有数据库集合的信息。
- 用户创建的集合不能在集合名中包含保留字 符’$‘。
子集合
组织集合的一种惯例是使用“.”分隔不同命名空间的子集合
数据库
数据库名可以是满足以下条件的任意UTF-8字符串
Note:
- 不能是空字符串(”“)。
- 不得含有/、\、.、”、*、<、>、:、|、?、$(一个空格)、\0(空字符)。基本上,只能使用ASCII中的字母和数字。
- 数据库名区分大小写,即便是在不区分大小写的文件系统中也是如此。简单起见,数据库名应全部小写。
- 数据库名最多64字节
注:数据库最终会变成文件系统里的文件,而数据库名就是相应的文件名,所以数据库名有如此多的限制。
MongoDB保留的数据库
admin
从身份验证的角度来讲,这是“root”数据库。如果将一个用户添加到admin数据库,这个用户将 自动获得所有数据库的权限。再者,一些特定的服务器端命令也只能从admin数据库运行,如列 出所有数据库或关闭服务器。
local
这个数据库永远都不可以复制,且一台服务器上的所有本地集合都可以存储在这个数据库中。
config
MongoDB用于分片设置时,分片信息会存储在 config
数据库中
Note: - 把数据库名添加到集合名前,得到集合的完全限定名,即命名空间(namespace)。例如,如果要使用cms数据库中的blog.posts集合,这个集合的命名空间就是cms.blog.posts。命名空间的长度不得超过121字节,且在实际使用中应小于100字节。
MongoDB Shell
基本操作(CRUD)
- 创建
|
|
查找,可添加查询条件
1 2 3
db.books.find() // Find All db.books.find().pretty() // 显示格式化后的数据 db.books.findOne() // Find One(默认返回第一个)
更新
update接受(至少)两个参数:第一个是限定条件(用于匹配待更新的文档),第二个是新的文档。
|
|
- 删除
|
|
数据类型
基本数据类型
String
:
1
|
字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。 |
Integer
:
1
|
整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。 |
Boolean
:
1
|
布尔值。用于存储布尔值(真/假)。 |
Double
:
1
|
双精度浮点值。用于存储浮点值。 |
Min/Max keys
:
1
|
将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。 |
Arrays
:
1
|
用于将数组或列表或多个值存储为一个键。 |
Timestamp
:
1
|
时间戳。记录文档修改或添加的具体时间。 |
Object
:
1
|
用于内嵌文档。 |
Null
:
1
|
用于表示空值或者不存在的字段 |
Symbol
:
1
|
符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。 |
Date
:
1 2 3 |
日期被存储为自新纪元以来经过的毫秒数,不存储时区: {"x" : new Date()} |
Object ID
:
1
|
对象 ID。用于创建文档的 ID。 |
Binary Data
:
1
|
二进制数据是一个任意字节的字符串。它不能直接在shell中使用。如果要将非UTF-8字符保存到数据库中,二进制数据是唯一的方式。 |
Code
:
1
|
代码类型。用于在文档中存储 JavaScript 代码。 |
Regular expression
:
1
|
正则表达式类型。用于存储正则表达式。 |
日期
在JavaScript中,Date类可以用作MongoDB的日期类型。创建日期对象时,应使用new Date(…),而非Date(…)。
数组
数组是一组值,他既能作为有序对象(如列表、栈或队列), 也能作为无序对象(如数据集)来操作。
|
|
db.test.find({“things”:true})
Note:
- 数组可包含不同数据类型的元素
- MonogoDB可理解数组结构,并能“深入”其中构建索引、执行查询或者更新。
内嵌文档
内嵌文档:即文档可以作为 键
的值
|
|
Note:
- 同数组一样,MongoDB能够“理解”内嵌文档的结构,并能“深入”其中构建索引、执行查询或者更新。
_id 和 ObjectId
MongoDB中存储的文档必须有一个 _id
键。 这个键的值可以是任意类型,默认是 ObjectId 对象,用于唯一标识文档。
Note:
- MongoDB中不同集合中的 _id
可以相同,但同一集合必须保证唯一
ObjectId
ObjectId是”_id”的默认类型。全局唯一。
Note: - ObjectId 采用12字节的存储空间,是一个由24个十六进制数字组成的字符串。ObjectId 的生成方式 - 最开始 4 字节:时间戳,单位秒 - 接下来 3 字节:主机的唯一标识符(机器名的散列值 hash) - 接下来 2 字节:进程标识符(pid),确保同一台机器上并发的多个进程(mongod)产生的 ObjectId 唯一 - 最后的 3 字节:自增的计数器, 确保相同进程同一秒产生的ObjectId也是不一样的。(1s最多允许每个进程拥有256^3=16777216)个不同的ObjectId
自动生成 _id
MongoDB的哲学:能交给客户端驱动程序来做的事情就不要交给服务器完成。
使用 MongoDB Shell
Note: 后面用到了再来仔细研读
- db.help()查看数据库级别的帮助
- db.foo.help()查看集合级别的帮助
使用 shell 执行脚本
$ mongo script1.js scripts2.js …
$ mongo –quiet server-1:30000/foo script1.js script2.js
$ load(“scripts1.js”)
创建 .mongorc.js 文件
.mongorc.js:该文件会在shell启动时自动运行,如果在启动shell时制定 --norc
参数,就可以禁止加载 .mongorc.js
When starting, mongo checks the user’s HOME directory for a JavaScript file named .mongorc.js. If found, mongo interprets the content of .mongorc.js before displaying the prompt for the first time. If you use the shell to evaluate a JavaScript file or expression, either by using the –eval option on the command line or by specifying a .js file to mongo, mongo will read the .mongorc.js file after the JavaScript has finished processing. You can prevent .mongorc.js from being loaded by using the –norc option.
定制 shell 提示
CRUD
插入
MongoDB 插入数据时, 只对数据进行最基本的检查:检查文档的基本结构,如果没有”_id”字段,就自动增加一个、检查大小,所有文档必须小于16M
删除
更新
MongoDB 更新操作是不可分割的:若是两个更新同时发生,先到达服务器的先执行,接着执行另外一个。所以,两个需要同时进行的更新会迅速接连完成,此过程不会破坏文档,最新的更新会取得胜利
文档替换
一个常见的错误是查询条件匹配到了多个文档,然后更新时由于第二个参数的存在就产生重复的 “_id” 值;数据库会抛出错误,任何文档都不会更新。
Note:
- 更新文档时总是要指定一个唯一的文档,推荐用
_id
匹配,且 _id 建立了索引,会提升效率。
修改器
文档只有一部分(字段)做修改时,可以使用原子性的更新修改器,对文档中指定的字段进行更新。
$set 修改
$set
指定一个字段的值。如果这个值不存在,则创建它。应用场景:更新模式或者增加用户自定义的键时很方便。例如 users
集合有如下文档:
|
|
几种应用场景:
- 更新喜欢的书:
|
|
- 喜欢很多本书时,可将键
favorite book
类型改为数据。即可修改键的类型:
|
|
- 不喜欢时可删除该键:
|
|
- 或者修改内嵌文档的键:key.child_key_name
Note:
- $set 可更新键值
- $set 可修改键值的类型
- $unset 可删除键
- $set 可更新内嵌文档的键值
- 增加、修改、删除键时,应该使用
$
修改器,否则会造成整个文档的替换
$unset 删除键
语法:{“$unset”: {“field1”:“”, …}} 释义:删除文档中指定的字段,若字段不存在则不操作 示例:
|
|
$inc 增加和减少
$inc
修改器用来增加已有键的值,或者该键不存在时创建它。应用场景:更新分析数据、因果关系、投票或者其他有变化的数值的地方。
- 用户余额加 50:
|
|
Note:
- $inc 只用来增加和减少数字
- $inc 只用于整形、长整形或双精度浮点型的值,用于其它类型会导致失败
$mul 乘法
语法:{$mul: {field: <number>
示例:
|
|
Note:
- The field to update must contain a numeric value.
$rename 重命名
语法:{"$rename":{<field1>: <new_name>, <field1>: <new_name>,...}}
释义:重命名文档中指定字段的名称
示例:
|
|
Note:
- The new field name must differ from the existing field name.
- If the field to rename does not exist in a document, $rename does nothing (i.e. no operation).
$min
语法:{“$min”:{“field”: < value>, …}}
释义:将文档中匹配到的字段的值和指定值(< value>)做比较,如果原值小于
指定值,则不更新
;若大于指定值,则更新。
示例:
|
|
Note:
- The $min operator can compare values of different types, using the BSON comparison order.
$max
与 $min 功能相反
$setOnInsert
注解:有时,需要在创建文档的同时创建字段并为它赋值,但是在之后的所有更新操作中,这个字段的值都不再改变,这就”$setOnInsert”的作用
|
|
|
|
Note:
- ”$setOnInsert” 只会在文档插入时设置字段的值。
$currentDate
数组修改器
$
基于位置的数组修改器: 通过数组下标(知道具体索引值) or 通过定位操作符($)
Acts as a placeholder(占位符) to update the first element that matches the query condition.
Note:
- 定位符只更新第一个匹配的数组元素。如果有多条匹配,则其他数据不会发生任何变化。
$[]
Acts as a placeholder to update all elements in an array for the documents that match the query condition.
$[< identifier>]
Acts as a placeholder to update all elements that match the arrayFilters condition for the documents that match the query condition.
$addToSet
Adds elements to an array only if they do not already exist in the set.
语法:{“$addToSet”:{“field”: value, …}}
释义:向数组中添加一个元素(一般用于update), 且保证了不会与数组原有元素重复,如果将要添加的元素已存在,则 do nothing.
示例:
|
|
- 将”$addToSet”和”$each”组合起来,可以添加多个不同的值,
|
|
Note:
- If the field is absent(缺席) in the document to update, $addToSet creates the array field with the specified value as its element.
- If the field is not an array, the operation will fail.
- If the value is an array, $addToSet appends the whole array as a single element.
$pop
Removes the first or last item of an array.
语法:{$pop: {“field”: <-1|1>, …}} 释义: - {“$pop”: “field”: -1}: 从数组头部删除一个元素 - {“$pop”: “field”: 1}: 从数组末尾删除一个元素 示例:
|
|
Note:
- The $pop operation fails if the
is not an array.
$pull
Removes all array elements that match a specified query.
语法:{$pull: {
|
|
$pullAll
Removes all matching values from an array.
语法:{ $pullAll: {
|
|
Note:
$push 添加元素
如果数组已经存在,$push
会向已有的数组末尾加入一个元素, 要是没有将创建一个新的数组。例如:有 user
集合如下
|
|
- 向 zhe 添加一个好友(field: friends):即向 friends 数组末尾添加一个元素
|
|
- 使用
$each
子操作符可以通过一次$push
操作添加多个值
|
|
- 使用
$slice
和$push
组合,可以限制数据的最大长度,即实际上可以得到一个包含N个元素的数组。
|
|
Note:
- 如果 $push 后数组元素小于 N, 则保留所有元素,如果大于 N, 则只保留最后N个元素(N为正数是则保留前 N 个元素)
- $push 和 $set 同时使用会出错:
The dollar ($) prefixed field '$push' in '$push' is not valid for storage.
|
|
$each
语法:
|
|
释义:$each
与 $push、$addToSet
结合使用,实现向数组字段添加多个元素的作用。
$position
语法:
|
|
释义:自v2.6加,配合$push使用表示往数组元素中的指定位置插入元素
$slice
语法:
|
|
释义:The
Value | Descriptions |
---|---|
Zero | To update the array |
Negative(正数) | To update the array |
Positive(负数) | To update the array |
$sort
语法:
|
|
释义:自v2.4加,配合$push使用,表示给文档中的指定数组元素排序,1是升序,-1是降序
修改器速度
填充因子(padding factor): 是MongoDB为每个新文档预留的增长空间
Upsert
upsert 是一种特殊的更新。要是没有找到符合更新条件的文档,就会以这个条件和更新文档为基础创建一个新的文档。如果找到了匹配的文档,则正常更新。
写入安全机制
写入安全(Write Concern) 是一种客户端设置,用于控制写入的安全级别。默认情况下,插入、删除和更新都会一直等待数据库响应(写入是否成功),然后才会继续执行。通常,遇到错误时,客户端会抛出一个异常。
MongoDB两种最基本的写入安全机制是应答式写入(acknowledged write) 和 非应答式写入(unacknowledged write) - 应答式写入: 默认方式,数据库会给出响应 - 非应答式写入:不会返回任何响应,so, 无法知道是否写入成功
查询
- 使用 $ 条件查询实现范围查询、数据集包含查询、不等式查询…
- 查询将放回一个数据库
游标
, 游标只会在你需要时才需要的文档批量返回 - 针对游标的元操作:offset、limit、sort
find 简介
向查询文档加入多个键值对时,将多个查询条件组合在一起会被解释成:条件1 and 条件2 and 条件3 and 条件N
|
|
指定需要返回的键
_id
: 默认情况下,该键总是被返回,即便是没有指定要返回这个键
- 指定需要的键, 例如只返回 “name”
|
|
- 剔除不用的键, 例如不需要 “name”
|
|
查询
比较操作符
$eq
$gt
$gte
$lt
$lte
$ne
$in
语法:{ field: { $in: [
释义:用于查询一个键与多个值进行匹配, 再加一个条件数组
示例:
|
|
$nin
与 $in 相对,$nin 将返回与数组中所有条件都不匹配的文档
逻辑操作符
$or
语法:{ $or: [ {
释义:条件或,接收一个包含所有可能条件的数组作为参数
示例:
|
|
Note: 下面是一个错误使用方式
|
|
Note:
- $or 第一个条件应该尽可能匹配更多的文档,这样才是最为高效的
$and
语法:{ $and: [ {
释义:条件与
示例:
|
|
$not
”$not”是元条件句,即可以用在任何其他条件之上。就拿取模运算符”$mod”来说。”$mod”会将查询的值除以第一个给定值,若余数等于第二个给定值则匹配成功。
”$not”与正则表达式联合使用时极为有用,用来查找那些与特定模式不匹配的文档
语法:{field: {$not: {
释义:查询与表达式不匹配的文档
示例:
|
|
$nor
语法:{ $nor: [ {
释义:查询与任一表达式都不匹配的文档
示例:
|
|
元素操作符
$exists
语法:{ field: { $exists:
释义:查询存在指定字段的文档
示例:
|
|
$type
语法:{field: {$type:
释义:查询类型为指定类型的文档,3.2版本添加alias别名,各种类型的Number及Alias如下
示例:
|
|
评估查询
$regex 正则表达式
MongoDB使用Perl兼容的正则表达式(PCRE)库来匹配正则表达式,任何PCRE支持的正则表达式语法都能被MongoDB接受。
语法:
|
|
释义:正则表达死查询
示例:
|
|
- i:正则表达式标志,是否区分大小写(i存在表示不区分)
$mod
语法:{ field: { $mod: [ 除数, 余数 ] } }
释义:取余条件查询
示例:查询 age 字段的值除以 2 余数为 0 的文档
|
|
$text
语法:
|
|
- $search: 关键词
- $language: 语言,不支持中文
- $caseSensitive: 是否区分大小写,默认 false
- $diacriticSensitive: 是否区分读音,默认 false
释义:文本索引查询
示例:
|
|
$where
语法:
释义:把一个含有JavaScript表达式的字符串或者是整个JavaScript函数转换到查询系统中,对内嵌文档不起作用
示例:
|
|
查询数组
$all
语法:{field: {$all: [
释义:匹配文档的数组字段中包含所有指定元素的文档
示例:
|
|
$elemMatch
语法:{filed: {$elemMatch: {
释义:匹配内嵌文档或数组中的部分 field
示例:假设有如下集合
|
|
|
|
Note:
- ”$elemMatch”将限定条件进行分组,仅当需要对一个内嵌文档的多个键操作时才会用到。
$size
语法:{field: {$size:
释义:匹配数组长度为指定大小的文档
示例:查询集齐五张福卡的人
|
|
Note:
- $size 不能与像 $gt… 等同时使用
查询内嵌文档
聚合查询
服务端脚本
游标
使用 skip 函数略过大量文档是会变得很慢…
不用 skip 对结果分页
文档按 Date 降序排列,然后将第一次查询结果的最后一个文档的 Date 作为下一次的查询条件
随机选取文档
优化算法:在插入文档时给每个文档都添加一个额外的随机键,这样,想要从集合中查找一个随机文档,只要计算一个随机数并将其作为查询条件就好了
See Also
Thanks to the authors 🙂
操作符相关
数组相关