我们总是喜欢拿“顺其自然” 来敷衍人生道路上的荆棘坎坷, 却很少承认,真正的顺其自然, 其实是竭尽所能之后的不强求,而非两手一摊的不作为。 --知乎 2020.08.1
mongoDB 学习平台:
第1章MongoDB简介
MongoDB(源自单词humongous)是一种较新的数据库,它没有表、模式、SQL或行的概念。它没有事务、ACID兼容性、连接、外键或其他许多容易在凌晨引起问题的特性。
1.1了解MongoDB哲学
1.1.1使用正确的工具处理正确的工作
MongoDB中最重要的哲学概念是:一鞋难合众人脚。
1.1.2天然缺少对事务的支持
数据库将不会包含事务的语义(用于保·证数据一致性和存储的元素),
1.1.3 BSON和MongoDB
BSON(二进制JSON的英文简称)的开放数据格式。大多数情况下,使用BSON取代JSON并不会改变处理数据的方式,BSON通过使计算机更容易处理和搜索文档的方式,使MongoDB处理速度变得更快。BSON还添加了一些标准JSON不支持的特性,包括数字数据(例如int32和int64)的许多扩展类型,以及支持处理二进制数据。
1.1.4采用非关系方式
改进关系型数据库性能的方式是非常直接的:购买更大更快的服务器。
MongoDB通过一种非常聪明的方式解决了这些活跃/活跃集群问题, MongoDB是以BSON文档格式存储数据的,所以数据是自包含的。尽管相似的数据文档被存储在一起,但各个文档之间并没有关系。你需要的所有东西都在同一个地方。
因为MongoDB查询将在文档中寻找特定的键和值,该信息可以轻松地被扩散到所有可用的服务器上。每台服务器都将检查该查询,并返回结果。这样,可扩展性和性能的提升几乎是线性的。
MongoDB并不提供主/主复制,两台不同的服务器都可以接受写入请求。不过,它支持分片,允许将数据分散到多台机器中,每台机器都将负责更新数据集的不同部分。
- 分片集群的好处是可以添加额外的分片,来增加部署中的资源能力,而不必更改任何应用程序代码。
- 非分片数据库部署仅限于垂直缩放:可以添加更多的内存/CPU/磁盘,但是这很快就会变得非常昂贵。
分片的部署也可以垂直缩放,但更重要的是,它们可以基于能力要求进行横向扩展(水平扩展):
一个分片集群可以包含更多、能买得起的商用服务器,而不是几个非常昂贵的服务器。水平扩展非常适于通过云实例和容器进行弹性供应。
1.2将所有组合在一起
1.2.1生成或创建键
MongoDB要求每个文档必须有唯一标识符;在MongoDB中,该标识符被称为id。
除非为该字段指定某个值,否则MongoDB将自动创建唯一值。MongoDB是一个分布式数据库,所以其主要目标之一是消除对共享资源的依赖(例如检查主键是否独一无二)。非分布式的数据库通常使用一个简单的主键,例如自动递增的序列号。
MongoDB的默认id格式是一个Objectld,它是一个12字节的唯一标识符,可以独立地在分布式环境中生成。
1.2.2使用键和值
MongoDB不要求每个文档必须含有相同的字段,也不要求同名的字段有相同类型的值。如果MongoDB中不含某个键值对,那它就被认为是不存在的。
1.2.3实现集合
在MongoDB中,集合就是一组类似元素的集合。其中的元素不必相似(MongoDB本质上是非常灵活的);不过,当我们开始学习索引和高级查询时,就会看到在集合中放置类似元素的优点。可以在一个集合中混合各种不同的元素,但几乎没有必要这么做。
MongoDB的目标是使生活变得轻松,所以你应该按照自己感觉正确的方式去实现。最后但并非最不重要的是,集合可以按需求即时创建。尤其是,在第一次尝试保存文档时,MongoDB将创建引用它的集合。这意味着可以按照需求即时创建集合(但并不是应该这么做)。因为MongoDB也允许动态地创建索引,执行其他数据库级别的命令,所以可以利用该特性构建出一些非常动态的应用。
1.2.4了解数据库
可能理解MongoDB中数据库的最简单方式就是将它看成一个集合的集合。
1.3了解特性列表
1.3.1 WiredTiger
首先,引入了MongoDB的可插拔存储API和WiredTiger,它是一个性能卓越的数据库引擎。
WiredTiger在MongoDB 3.0中引入,是一个可选的存储引擎,现在是MongoDB 3.2的默认存储引擎。WiredTiger本身就使MongoDB达到一个全新水平,取代了内部数据存储和管理的旧MMAP模型。
WiredTiger允许MongoDB更好地优化驻留在内存中的数据和驻留在磁盘上的数据,而没有以前的杂乱溢出。其结果是,对所有用户而言, WiredTiger往往是一个真正的性能增益。
WiredTiger也更好地优化了数据存储在磁盘上的方式,提供了一个内置的压缩API,大大节省了磁盘空间。可以说,在安装了WiredTiger的机器上, MongoDB使数据库迈出了一大步。
1.3.2使用面向文档存储(BSON)
BSON更易于遍历(即浏览),遍历索引页非常快。尽管比起JSON, BSON需要稍微多一些的硬盘空间,但这并不是问题,
MongoDB可跨机器扩展。多占用一点硬盘空间,换来更好的查询和索引性能。
WiredTiger存储引擎支持多个压缩库,默认启用索引和数据压缩。压缩级别默认可以在每个服务器上设置,也可以在每个集合(在创建时)设置。
在存储数据时,较高的压缩级别会使用更多CPU,但可节省大量磁盘空间。使用BSON的第二个关键优点在于,很容易将BSON数据快速转换为编程语言的原生数据格式。如果以纯JSON方式存储数据,就需要添加一个较高级别的转换。
BSON也提供了对JSON的一些扩展 例如,通过BSON可以存储二进制数据,以及处理特定的数据类型。
因此, BSON可以存储任何JSON文档,但有效的BSON文档可能不是有效的JSON,
1.3.8存储二进制数据
GridFS是MongoDB在数据库中存储二进制数据的解决方案。
BSON支持在一个文档中存储最多16MB的二进制数据,这可能已经可以满足你的需求。
GridFS通过在files集合中存储文件的信息(称为元数据)来实现。数据本身被分成多块(称为信息块)存储在chunks集合中。这种方式使数据存储既简单又有扩展性:还使范围操作(例如获取文件的特定部分)变得更简单通常来说,我们将通过编程语言对应的MongoDB驱动来使用GridFS
1.3.9复制数据
MongoDB提供了包含主/从复制特性的安全网络,这种情况下只有一个数据库可以处于活跃状态,并且可以在任何时间写入,
复制集有一台主服务器(类似于主/从复制中的主服务器),它将处理所有来自客户端的请求。因为在指定的复制集中只有一台主服务器,它可以保证所有写入都会被正确处理。当写入操作·发生时,该操作也会被写入主服务器的oplog集合中。oplog集合将被复制到辅助服务器(可能有许多),并帮助它们将数据更新到与主服务器一致的状态。一旦主服务器出现故障,辅助服务器中的某一台将会成为主服务器,并负责处理所有来自客户端的写入请求。应用驱动将自动检测副本集配置或副本集状态的任何更改,根据更新的副本集状态重新连接。为让副本集维护主服务器,大多数健康的副本节点必须能够相互连接。例如,一套3个节点的副本集需要两个健康的节点来维护一个主服务器。
1.3.10实施分片
对于涉及大规模部署的应用, 自动分片可能是MongoDB最重要和最常用的特性。
在自动分片场景中, MongoDB将处理所有数据的分割和重组。它将保证数据进入正确的服务器,并以最高效的方式运行查询和重组结果。
事实上,从开发者的角度看,使用含有数百个分片的MongoDB数据库和使用单个MongoDB数据库并没有区别。与此同时,如果刚刚开始构建第一个基于MongoDB的网站,那么可能单实例MongoDB就足以满足需求(
1.3.11使用map和reduce函数
1.3.12聚集框架
1.4获取帮助
1.4.1访问网站
1.4.2剪切和粘贴MongoDB代码
1.4.3在Google小组中寻找解决方案决方案
第2章安装MongoDB
2.1选择版本
2.2在系统中安装MongoDB
2.2.1在Linux中安装MongoDB
[root@liruilong ~]# cd /etc/yum.repos.d
[root@liruilong yum.repos.d]# vim mongodb-org-4.0.repo
[mongdb-org]
name=MongoDB Repository
baseurl=http://mirrors.aliyun.com/mongodb/yum/redhat/7Server/mongodb-org/4.0/x86_64/
gpgcheck=0
enabled=1
# yum update
2.安装MongoDB
安装命令:
yum -y install mongodb-org
安装完成后
查看mongo安装位置 whereis mongod
查看修改配置文件 : vim /etc/mongod.conf
bindIp: 172.0.0.1 改为 bindIp: 0.0.0.0
(注意冒号与ip之间需要一个空格)
3.启动MongoDB
启动mongodb :sudo systemctl start mongod.service
停止mongodb :sudo systemctl stop mongod.service
2.2.2在Windows中安装MongoDB
2.3运行MongoDB
2.3.1先决条件
2.3.2研究安装目录布局
2.3.3使用MongoDB shell
> show dbs
admin 0.000GB
config 0.000GB
demo200712 0.000GB
local 0.000GB
test 0.000GB
> use demo200712
switched to db demo200712
> show collections
movie
> show users
2.4添加额外的驱动
2.4.1 安装PHP驱动
2.4.2确 PHP安装正确
2.4.3安装Python驱动
2.4.4确认PyMongo安装正确
2.5小结
第3章数据模型
3.1设计数据库
3.1.1集合的更多细节
集合是MongoDB中的一个常用术语。可将集合看成存储文档(即数据)的容器,如图3-1所示。
数据库集合文档图3-1 MongoDB数据库模型现在将MongoDB的数据库模型与关系数据库的典型模型做比较
MongoDB中有几种不同类型的集合。默认的集合按照大小进行扩展:添加的数据越多,集合就变得越大。
还可以定义固定大小(capped)的集合。这些固定大小的集合只可以包含特定数量的数据,最老的文档将被新增的文档替代
MongoDB中的所有集合都有唯一的名称。
在使用createCollection函数创建集合时,其中的名称应该以字母或下划线()开头。名字中可以包含数字和字母;
不过$符号是MongoDB的保留关键字。类似地,其中不允许使用空白字符串(" ");也不可以使用null字符,并且不可以以"system."字符串开头。
MongoDB支持的集合名称的最大长度为128,很明显,并没有任何实际的理由需要创建如此长的名称。运行默认MMAPVI存储引擎的单个数据库默认最多可以创建24 000个名称空间, WiredTiger存储引擎没有这个限制。
每个集合至少包含两个名称空间:一个用于集合自身,另一个用于集合中创建的第一个索引。
如果为每个集合添加更多索引,将使用更多名称空间。这意味着从理论上讲,如果每个集合都只含有一个索引,那么每个数据库默认最多可以拥有12000个集合。不过在执行MongoDB服务应用(mongod)时,可以通过提供nssize参数,把名称空间的数目至多t 到2047MB.
3.1.2使用文档
文档由键/值对组成。例如, "Type": "Book"由键Type和值Book组成。 键的类型为字符串,但可以使用许多不同类型的数据作为值。值可以是任何类型的数据,例如数组甚至是二进制数据。 MongoDB使用BSON格式存储数据 所有可以添加到文档中的数据类型:
- String: 常用数据类型,包含一串文本(或任何其他种类的字符),该数据类型常用于存储文本值(例如, "Country": "Japan").
- Integer(32位和64 ): 该数据类型常用于存储数值(例如, 1"Rank": 1)。注意在整数的前后没有引号。
- Boolean: 该数据类型的值要么为真,要么为假。
- Double: 该数据类型用于存储浮点数。
- Min/Max keys: 该数据类型分别用于与BSON中的最低和最高值加以比较。
- Arrays: 该数据类型用于存储数组(例如, ["Membrey, Peter", "Plugge, Eelco", "Hows.David").
- Timestamp: 该数据类型用于存储时间戳。可以方便记录文档修改或添加的时间。
- Object: 该数据类型用于存储嵌入文档。
- Null: 该数据类型用于存储Null值。
- Symbol: 该数据类型的用法与字符串一致;不过,通常该数据类型将被语言保留用于特定的符号类型。
- Date: 该数据类型用于存储UNIX时间格式的当前日期或时间(POSIX时间).
- Object ID: 该数据类型用于存储文档的ID.
- Binary data: 该数据类型用于存储二进制数据。
- Regular expression: 该数据类型用于正则表达式。所有选项都通过按字母顺序提供的特殊字符表示。
- JavaScripr Code: 该数据类型用于JavaScript代码。 比较在文档中内嵌信息和引用另一个文档中的信息这两种方式的优劣。
3.1.3在文档中内嵌或引用信息
MongoDB(和其他非关系数据库)中,内嵌此类型信息会更加简单。毕竟,文档本身能够实现这样的操作。采用这种方式将保持数据库简洁,保证所有相关的信息都存储在单个·文档中.
使用MongoDB的经验法则是:尽可能地使用内嵌数据,这种方式要高效得多
3.1.4创建id字段
MongoDB数据库中的所有对象都包含唯一标识符,用于区分不同的对象。该标识符被称作id键,它将在创建集合时自动添加到所有文档中。
id键是添加到所有新创建文档中的第1个属性。即使不告诉MongoDB创建该键,它也会这么做。
id的类型默认被设置为由12字节二进制数据组成的BSON数据类型。
这个12字节的值包含4字节的时间戳(从1970年1月1日以来的秒数)、 3字节的机器ID、2字节的进程ID和3字节的计数器。
3.2构建索引
索引是一种数据结构,用于收集集合中文档特定字段的值的信息。
MongoDB的查询优化器使用该数据结构对集合中的文档进行快速排序。
记住,索引保证了在文档中查询数据的速度。基本上,可将索引看成已经执行并存储了结果的预定义查询。可以想象,这极大地增强了查询性能。
创建索引的最大优点在于在查询常用信息时会非常快捷,因为这些查询不需要遍历整个数据库以收集该信息。-旦掌握索引,创建(或删除)索引相对就会很容易。
每个集合最多可以拥有40个索引。通常来说,这远超个人的需要,不过某天你有可能不经意间就达到这个限制。
查看索引:
3.3使用地理空间索引.
索引类型之外, MongoDB还支持地理空间索引,可用于处理基于位置的查询。
例如,可以使用该特性查找距用户当前位置最近的已知目标。或者重新定义搜索,查询距离目前位置最近的,餐馆。
如果希望创建一个应用,希望根据指定的客户ZIP代码找到最近的分公司,那么这种类型的查询将特别有用。准备包含地理空间信息的文档必须有一个子对象或数组(第一个元素指定了对象类型,紧接着是该元素的经度和纬度),如下所示:
参数type可用于指定文档的GeoJSON对象类型,可以是
Point. MultiPoint, LineString.MultiLineString, MultiPolygon, Polygon或GeometryCollection。
如预料的一样,
- Point类型用于指定某个条目(本例中为餐馆)所在的准确位置,因此需要两个值:经度和纬度。
- LineString可用于指定某个沿着特定路线扩展的条目(例如街道),因此需要起点和终点,
- Polygon类型可用于指定(非默认的)图形(购物区域)。使用该类型时,需要保证起点和终点,是一致的,从而可以闭合这个环。另外,该点的坐标将通过在数组中内嵌数组的方式提供,
- 所有Multi版本(MultiPoint. MultiLineString等)是选中数据类型的数组,如下面的MultiPoint
> db.restaurants.insert({})
WriteResult({ "nInserted" : 1 })
> db.restaurants.insert({name:"liruilong",loc:{type:"Point",coordinates:[52.370451,5.217497]} })
WriteResult({ "nInserted" : 1 })
> db.streets. insert( (name: "Westblaak", loc: (type: "Linestring", coordinates: [[52.36881,4.890286] , (52.368762,4.890021] }}})
2020-10-27T08:05:00.452+0800 E QUERY [js] SyntaxError: missing ) in parenthetical @(shell):1:25
> db. stores.insert( (name: "SuperMal1", loc: {type: "Polygon", coordinates:[ [[52.146917,5.374337], [52.146966,5.375471], [52.146722,5.375085], [52.146744,5.374371,[52.146917,5.374337] ]]}})
2020-10-27T08:06:09.862+0800 E QUERY [js] SyntaxError: missing ) in parenthetical @(shell):1:24
> db.restaurants. insert ({name: "Shabu Shabu", loc: ( type: "MultiPoint", coordinates: [52.1487441, 5.3873406], [52.3569665,4.890517] }})
2020-10-27T08:16:19.440+0800 E QUERY [js] SyntaxError: missing ) in parenthetical @(shell):1:57
> db.restaurants.ensureindex({loc:"2dsphere"})
2020-10-27T08:18:01.426+0800 E QUERY [js] TypeError: db.restaurants.ensureindex is not a function :
@(shell):1:1
3.4可插拔的存储引擎
MongoDB的存储引擎是数据库的一部分,负责把数据存储在磁盘上。
在3.0版本之前,只能使用MongoDB原生的MMAPVI存储引擎。在3.2之前的任何版本中,这仍然是默认的存储引擎,但现在可以选择使用WiredTiger存储引擎替代,
3.5在真实世界中使用MongoDB
3.6小结
第4章使用数据
4.1浏览数据降
在MongoDB在第一次存储数据时自动创建数据库和集合。要切换到已有的数据库或者创建新的数据库,可在shell中使用use函数,
在命令后加上希望使用的数据库名称即可,无论它存不存在。
查看可用的数据库:
查看所有集合:
4.2在集合中插入数据
将文档插入到集合中后,返回WriteResult)的输出。WriteResult)将携带操作的状态,以及执行的动作。当插入文档时,返回nInserted属性以及插入文档的数量。
键名约束:
- $字符不能是键名的第一个字符。例如$tags.
- 圆点[.]不能出现在键名中。例如ta.gs.
- 名称_id被保留用作主键ID:尽管不推荐,但可以保存任何唯一值,例如字符串或整数。
创建集合时也存在一些限制。
- 集合的名称(包括数据库名和“.”分隔符)不能超过128个字符。
- 空字符串(" ")不能用作集合名称。
- 集合名必须以字母或下划线开头。
- 集合名system被MongoDB保留,不能使用。集合名不能包含null字符“0".
4.3查询数据
函数find()提供了从同一集合的多个文档中获取数据的最简单方式。它将是最常用的函数之一。
假设已经在library数据库的media集合中插入了之前的两个样例。如果在该集合上使用findo),结果将是其中的所有文档:
> show collections
media
> db.media.find()
{ "_id" : ObjectId("5f99fdc1540cc5e47fad265f"), "name" : "李瑞龙", "age" : "26", "fay" : [ ] }
>
> db.demo.find({type"1"})
> db.demo.find({type:"1"})
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661"), "abstractFileId" : "2c46051d7ad8435d90854f93388a7f3f", "createTime" : "2019-09-06T02:55:00.705Z", "updateTime" : "2019-09-06T02:55:00.705Z", "appId" : "", "fileId" : "7708cd240102499fb2ea76be4ed30b8b", "groupId" : "2a35477e083d40f38e9c49ee6821264c", "fileName" : "测试.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 0, "fileLastModified" : 1567738500562, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "d41d8cd98f00b204e9800998ecf8427e", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2019-09-06T02:55:00.705Z", "path" : "/2a35477e083d40f38e9c49ee6821264c/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "fileName" : "test1.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "c4ca4238a0b923820dcc509a6f75849b", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
> db.demo.find({type:"1"},{fileNmae:1})
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661") }
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663") }
插入的参数(Title: 1)表示只返回标题字段中的信息。总是返回id字段,除非使用Lid: 0排除它。
> db.demo.find({type:"1"},{fileName:0})
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661"), "abstractFileId" : "2c46051d7ad8435d90854f93388a7f3f", "createTime" : "2019-09-06T02:55:00.705Z", "updateTime" : "2019-09-06T02:55:00.705Z", "appId" : "", "fileId" : "7708cd240102499fb2ea76be4ed30b8b", "groupId" : "2a35477e083d40f38e9c49ee6821264c", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 0, "fileLastModified" : 1567738500562, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "d41d8cd98f00b204e9800998ecf8427e", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2019-09-06T02:55:00.705Z", "path" : "/2a35477e083d40f38e9c49ee6821264c/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "c4ca4238a0b923820dcc509a6f75849b", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
> db.demo.find({type:"1"},{fileName:1})
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661"), "fileName" : "测试.txt" }
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "fileName" : "test1.txt" }
>
4.3.1使用点号
> db.demo.find({"extend.filestate":""},{fileName:1})
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661"), "fileName" : "测试.txt" }
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "fileName" : "test1.txt" }
> db.demo.find({"extend.filestate":"1"},{fileName:1})
> db.demo.find({"fileName":"测试.txt"},{fileName:1})
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661"), "fileName" : "测试.txt" }
> db.demo.find({"fileName":"测试.txt","test1.txt"},{fileName:1})
2020-10-29T08:05:15.691+0800 E QUERY [js] SyntaxError: missing : after property id @(shell):1:45
4.3.2使用函数sort, limit和skip
通过使用sort函数可以对查询返回的结果进行排序。可分别使用1或-1将结果按照升序或条序排序。该函数与SQL中的ORDER BY语句类似,它将使用键的名称和排序方法作为条件。
> db.demo.sort({fileName:1})
2020-10-29T08:10:19.639+0800 E QUERY [js] TypeError: db.demo.sort is not a function :
@(shell):1:1
> db.demo.find().sort({fileName:1})
{ "_id" : ObjectId("5f9a028c540cc5e47fad2662"), "abstractFileId" : "88f5184ea0d04ba4a6db7585bf968ef9", "createTime" : "2018-11-15T09:01:27.593Z", "updateTime" : "2018-11-15T09:01:27.593Z", "fileName" : "5ad3da678c4041f08f4d049be5e540ed", "fileSize" : 0, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : false, "type" : "0", "shareSign" : 1, "userSign" : "0230fa68b633442dac7f8c2ee01b4265", "effectiveDate" : "2018-11-15T09:01:27.593Z", "path" : null, "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "fileName" : "test1.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "c4ca4238a0b923820dcc509a6f75849b", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661"), "abstractFileId" : "2c46051d7ad8435d90854f93388a7f3f", "createTime" : "2019-09-06T02:55:00.705Z", "updateTime" : "2019-09-06T02:55:00.705Z", "appId" : "", "fileId" : "7708cd240102499fb2ea76be4ed30b8b", "groupId" : "2a35477e083d40f38e9c49ee6821264c", "fileName" : "测试.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 0, "fileLastModified" : 1567738500562, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "d41d8cd98f00b204e9800998ecf8427e", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2019-09-06T02:55:00.705Z", "path" : "/2a35477e083d40f38e9c49ee6821264c/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
在不指定参数的情况下,这是默认的排序顺序。还可以使用-1标志来进行降序排序。
注意:如果指定一个不存在的键用于排序,结果的顺序就是未定义的
> db.demo.find().sort({fileName:-1})
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661"), "abstractFileId" : "2c46051d7ad8435d90854f93388a7f3f", "createTime" : "2019-09-06T02:55:00.705Z", "updateTime" : "2019-09-06T02:55:00.705Z", "appId" : "", "fileId" : "7708cd240102499fb2ea76be4ed30b8b", "groupId" : "2a35477e083d40f38e9c49ee6821264c", "fileName" : "测试.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 0, "fileLastModified" : 1567738500562, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "d41d8cd98f00b204e9800998ecf8427e", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2019-09-06T02:55:00.705Z", "path" : "/2a35477e083d40f38e9c49ee6821264c/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "fileName" : "test1.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "c4ca4238a0b923820dcc509a6f75849b", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a028c540cc5e47fad2662"), "abstractFileId" : "88f5184ea0d04ba4a6db7585bf968ef9", "createTime" : "2018-11-15T09:01:27.593Z", "updateTime" : "2018-11-15T09:01:27.593Z", "fileName" : "5ad3da678c4041f08f4d049be5e540ed", "fileSize" : 0, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : false, "type" : "0", "shareSign" : 1, "userSign" : "0230fa68b633442dac7f8c2ee01b4265", "effectiveDate" : "2018-11-15T09:01:27.593Z", "path" : null, "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "fileExtend" : { }, "version_" : 1 }
> db.demo.find().sort({liruilong:-1})
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661"), "abstractFileId" : "2c46051d7ad8435d90854f93388a7f3f", "createTime" : "2019-09-06T02:55:00.705Z", "updateTime" : "2019-09-06T02:55:00.705Z", "appId" : "", "fileId" : "7708cd240102499fb2ea76be4ed30b8b", "groupId" : "2a35477e083d40f38e9c49ee6821264c", "fileName" : "测试.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 0, "fileLastModified" : 1567738500562, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "d41d8cd98f00b204e9800998ecf8427e", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2019-09-06T02:55:00.705Z", "path" : "/2a35477e083d40f38e9c49ee6821264c/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a028c540cc5e47fad2662"), "abstractFileId" : "88f5184ea0d04ba4a6db7585bf968ef9", "createTime" : "2018-11-15T09:01:27.593Z", "updateTime" : "2018-11-15T09:01:27.593Z", "fileName" : "5ad3da678c4041f08f4d049be5e540ed", "fileSize" : 0, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : false, "type" : "0", "shareSign" : 1, "userSign" : "0230fa68b633442dac7f8c2ee01b4265", "effectiveDate" : "2018-11-15T09:01:27.593Z", "path" : null, "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "fileName" : "test1.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "c4ca4238a0b923820dcc509a6f75849b", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
通过使用limit)函数可以限制返回结果的最大数目。。
该函数只需要一个参数:希望返回的结果的数目。如果使用的参数为0,将返回所有结果。
> db.demo.find().sort({fileName:-1}).limit(1)
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661"), "abstractFileId" : "2c46051d7ad8435d90854f93388a7f3f", "createTime" : "2019-09-06T02:55:00.705Z", "updateTime" : "2019-09-06T02:55:00.705Z", "appId" : "", "fileId" : "7708cd240102499fb2ea76be4ed30b8b", "groupId" : "2a35477e083d40f38e9c49ee6821264c", "fileName" : "测试.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 0, "fileLastModified" : 1567738500562, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "d41d8cd98f00b204e9800998ecf8427e", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2019-09-06T02:55:00.705Z", "path" : "/2a35477e083d40f38e9c49ee6821264c/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
> db.demo.find().sort({fileName:-1}).limit(0)
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661"), "abstractFileId" : "2c46051d7ad8435d90854f93388a7f3f", "createTime" : "2019-09-06T02:55:00.705Z", "updateTime" : "2019-09-06T02:55:00.705Z", "appId" : "", "fileId" : "7708cd240102499fb2ea76be4ed30b8b", "groupId" : "2a35477e083d40f38e9c49ee6821264c", "fileName" : "测试.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 0, "fileLastModified" : 1567738500562, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "d41d8cd98f00b204e9800998ecf8427e", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2019-09-06T02:55:00.705Z", "path" : "/2a35477e083d40f38e9c49ee6821264c/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "fileName" : "test1.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "c4ca4238a0b923820dcc509a6f75849b", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a028c540cc5e47fad2662"), "abstractFileId" : "88f5184ea0d04ba4a6db7585bf968ef9", "createTime" : "2018-11-15T09:01:27.593Z", "updateTime" : "2018-11-15T09:01:27.593Z", "fileName" : "5ad3da678c4041f08f4d049be5e540ed", "fileSize" : 0, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : false, "type" : "0", "shareSign" : 1, "userSign" : "0230fa68b633442dac7f8c2ee01b4265", "effectiveDate" : "2018-11-15T09:01:27.593Z", "path" : null, "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "fileExtend" : { }, "version_" : 1 }
还可以使用skip0函数忽略掉集合中的前n个文档。结合limit和skip可以实现分页;
> db.demo.find().sort({fileName:-1}).limit(2)
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661"), "abstractFileId" : "2c46051d7ad8435d90854f93388a7f3f", "createTime" : "2019-09-06T02:55:00.705Z", "updateTime" : "2019-09-06T02:55:00.705Z", "appId" : "", "fileId" : "7708cd240102499fb2ea76be4ed30b8b", "groupId" : "2a35477e083d40f38e9c49ee6821264c", "fileName" : "测试.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 0, "fileLastModified" : 1567738500562, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "d41d8cd98f00b204e9800998ecf8427e", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2019-09-06T02:55:00.705Z", "path" : "/2a35477e083d40f38e9c49ee6821264c/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "fileName" : "test1.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "c4ca4238a0b923820dcc509a6f75849b", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
> db.demo.find().sort({fileName:-1}).skip(2)
{ "_id" : ObjectId("5f9a028c540cc5e47fad2662"), "abstractFileId" : "88f5184ea0d04ba4a6db7585bf968ef9", "createTime" : "2018-11-15T09:01:27.593Z", "updateTime" : "2018-11-15T09:01:27.593Z", "fileName" : "5ad3da678c4041f08f4d049be5e540ed", "fileSize" : 0, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : false, "type" : "0", "shareSign" : 1, "userSign" : "0230fa68b633442dac7f8c2ee01b4265", "effectiveDate" : "2018-11-15T09:01:27.593Z", "path" : null, "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "fileExtend" : { }, "version_" : 1 }
> db.demo.find().sort({fileName:-1}).limit(1).skip(2)
{ "_id" : ObjectId("5f9a028c540cc5e47fad2662"), "abstractFileId" : "88f5184ea0d04ba4a6db7585bf968ef9", "createTime" : "2018-11-15T09:01:27.593Z", "updateTime" : "2018-11-15T09:01:27.593Z", "fileName" : "5ad3da678c4041f08f4d049be5e540ed", "fileSize" : 0, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : false, "type" : "0", "shareSign" : 1, "userSign" : "0230fa68b633442dac7f8c2ee01b4265", "effectiveDate" : "2018-11-15T09:01:27.593Z", "path" : null, "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "fileExtend" : { }, "version_" : 1 }
可在find()函数中使用快捷方式忽略并限制结果的数目: fnd ( {},{} ,10,20).这里,将首先:略开头的20个文档,然后将结果数目限10个
> db.demo.find({},{},2,1)
{ "_id" : ObjectId("5f9a028c540cc5e47fad2662"), "abstractFileId" : "88f5184ea0d04ba4a6db7585bf968ef9", "createTime" : "2018-11-15T09:01:27.593Z", "updateTime" : "2018-11-15T09:01:27.593Z", "fileName" : "5ad3da678c4041f08f4d049be5e540ed", "fileSize" : 0, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : false, "type" : "0", "shareSign" : 1, "userSign" : "0230fa68b633442dac7f8c2ee01b4265", "effectiveDate" : "2018-11-15T09:01:27.593Z", "path" : null, "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "fileName" : "test1.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "c4ca4238a0b923820dcc509a6f75849b", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
> db.demo.find({},{},2,2)
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "fileName" : "test1.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "c4ca4238a0b923820dcc509a6f75849b", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
> db.demo.find({},{},2,3)
>
4.3.3 使用固定集合、自然顺序和$natural
在MongoDB中使用查询时,需要注意固定集合、自然顺序和$natural.
自然顺序是数据库中集合的原生排序方法。所以,在查询集合中的文档时,如果没有显式指定排序顺序,结果将默认按照前向自然顺序返回。这通常与文档插入的顺序一致:不过,自然集合的自然顺序没有定义,可能取决于文档增长模式、用于查询的索引和所使用的存储引擎。
固定集合(capped collection)是数据库的一种集合,它的自然顺序保证与文档插入的顺序一致。保证自然顺序一直与文档插入顺序一致,这一点在需要将查询的结果严格按照文档插入顺序排序时非常有用。
固定集合还有另一个优点:大小固定。一旦固定集合达到设置的大小,最老的数据将被删除,最新的数据将被添加到末端,保证自然顺序与文档插入的顺序一致。该类型的集合可用于日志和自动归档记录
与标准集合不同,固定集合必须使用createCollection 函数,以显式方式创建。必须使用参数指定集合的大小(单位为字节),
固定集合保证了自然顺序与插入顺序一致,那么在查询数据时,就不需要再使用任何特殊的参数、任何其他特殊的命令或函数,除非希望逆转默认结果的顺序。这时将用到natural参数。例如,假设希望找到固定集合中最近的10条记录,该集合用于保存登录失败的记录。可使用Snatural参数来实现:
> db.createCollection("audit",{capped:true,size:20480})
{ "ok" : 1 }
> db.audit.find().sort({ $natural:-1}).limit(10)
>
已经添加到固定集合中的文档可以更新,但文档大小不能改变,如果出现这种情况,更新将会失败。也不可以从固定集合中删除文档,相反,如果希望删除文档,就必须删除整个集合并重建。
稍后将详细讲解删除集合的方法.还可以使用max:参数限制添加到固定集合中的文档数量,创建集合时使用该参数。
不过,必须注意保证集合有足够的空间容纳这些文档。如果在文档数目达到上限之前,数据大小先达到上限,那么最老的文档将被删除。
MongoDB shell包含一个工具,可用于检查现有集合已经使用的空间大小,无论是固定集合还是普通集合都可以查看。使用validate()函数调用该工具即可。
如果希望评估一个集合可能会变得多大,那么该方法非常有用。如前所述,可使用max:参数限制插入到固定集合中的文档数目,如下所示:
> db.createCollection("sudit100",{ capped:true,size:20,max:1000})
{ "ok" : 1 }
> db.sudit100.stats()
{
"ns" : "listFiles.sudit100",
"size" : 0,
"count" : 0,
"storageSize" : 4096,
"capped" : true,
"max" : 1000,
"maxSize" : 256,
"sleepCount" : 0,
"sleepMS" : 0,
"wiredTiger" : {
"metadata" : {
"formatVersion" : 1
},
............................ }
},
"nindexes" : 1,
"totalIndexSize" : 4096,
"indexSizes" : {
"_id_" : 4096
},
"ok" : 1
}
4.3.4获取单个文档
如果只希望返回一个结果,那可以使用findOne()函数来获取集合中的单个文档。该结果将与使用limit(1)函数得到的结果一致。
//db.media.find()
db.media.findOne()
{
"_id" : ObjectId("5f98bd6de0b9f4383bcce138"),
"name" : "李瑞龙",
"age" : "26",
"fay" : [
"爸爸",
"妈妈",
"妹妹"
]
}
4.3.5使用聚集命令
聚集命令中的3个函数: count, distinct和group.除了这3个基本的聚集函数, MongoDB还包含一个聚集框架。这个强大特性可以在不使用映射/归约框架的情况下,计算聚集结果。
count()
> show collections
audit
demo
media
sudit100
> db.demo.count()
3
> db.sudit100.count()
0
> db.media.count()
2
> db.demo.find({type:"1"}).count()
2
> db.demo.find({type:"1"}).limit(1).skip(3)
> db.demo.find({type:"1"}).limit(1).skip(2)
> db.demo.find({type:"1"}).limit(1).skip(1)
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "fileName" : "test1.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "c4ca4238a0b923820dcc509a6f75849b", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
> db.demo.find({type:"1"}).limit(1).skip(1).count(true)
1
distinct()
> db.demo.find({type:"1"}).limit(1).skip(1).count(true)
1
> db.demo.distinct("type")
[ "0", "1" ]
> db.demo.distinct("fileName")
[ "5ad3da678c4041f08f4d049be5e540ed", "test1.txt", "测试.txt" ]
MongoDB的group命令的目的是返回一个已分组元素的数组。
函数group()接受3个参数: key, initial和reduce.参数key指定希望使用哪个键对结果进行分组
参数initial允许为每个已分组的结果提供基数(元素开始统计的起始基数),如果希望返回指定"的数字,这个参数就应默认为0.
reduce把所有类似的条目分组在一起。它接受两个参数:正在遍历的当前文档和聚集计数对象。在接下来的样例中,这些参数被称为items和prev,实质上, reduce参数在每遇到一个匹配标题的文档时都将把总数加1
> db.demo.group( { key:{fileName:true}, initial:{Total:0}, reduce:(items,prev)=>{ prev.Total += 1 } })
[
{
"fileName" : "测试.txt",
"Total" : 1
},
{
"fileName" : "5ad3da678c4041f08f4d049be5e540ed",
"Total" : 1
},
{
"fileName" : "test1.txt",
"Total" : 1
}
]
>
除了key, initial和reduce参数,还可以指定另外3个可选参数:
- keyf:如果不希望使用文档中已有的键对结果进行分组,可以使用该参数替代key参数。此时,可以使用另一个指定了如何分组的函数对结果进行分组。
- cond:可以使用该参数指定一个额外的语句条件,文档必须满足该条件才能参加分组。可以像使用find()查询一样使用该参数搜索集合中的文档。如果未设置该参数(默认),那么集合中所有的文档都将被检查。
- finalize:可以使用该参数指定一个函数,用于在最终结果返回之前执行。例如,可以计算平均数或执行计数,并在结果中包含该信息。
函数group()目前在分片环境中无法正常工作,因此,在这种环境中应该使用mapreduce).另外,
在groupO)函数的输出结果中包含的键不能超过20 000个,否则将会抛出异常。此类情况也可以通过mapreduce)来处理。
4.3.6使用条件操作符
执行大于和小于比较以下特殊参数可用于在查询中执行大于和小于比较: $gt. $lt, $te和$lte。
- $gu(大于)参数。使用该参数指定文档中的某个整数必须大于指定的值时,才能在结果中返回:
> db.demo.find({fileSize:{$gte:0 }},{"fileName":0})
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661"), "abstractFileId" : "2c46051d7ad8435d90854f93388a7f3f", "createTime" : "2019-09-06T02:55:00.705Z", "updateTime" : "2019-09-06T02:55:00.705Z", "appId" : "", "fileId" : "7708cd240102499fb2ea76be4ed30b8b", "groupId" : "2a35477e083d40f38e9c49ee6821264c", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 0, "fileLastModified" : 1567738500562, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "d41d8cd98f00b204e9800998ecf8427e", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2019-09-06T02:55:00.705Z", "path" : "/2a35477e083d40f38e9c49ee6821264c/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a028c540cc5e47fad2662"), "abstractFileId" : "88f5184ea0d04ba4a6db7585bf968ef9", "createTime" : "2018-11-15T09:01:27.593Z", "updateTime" : "2018-11-15T09:01:27.593Z", "fileSize" : 0, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : false, "type" : "0", "shareSign" : 1, "userSign" : "0230fa68b633442dac7f8c2ee01b4265", "effectiveDate" : "2018-11-15T09:01:27.593Z", "path" : null, "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "c4ca4238a0b923820dcc509a6f75849b", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
> db.demo.find({fileSize:{$gt:0 }},{"fileName":0})
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "c4ca4238a0b923820dcc509a6f75849b", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
> db.demo.find({fileSize:{$gt:1 }},{"fileName":0})
> db.demo.find({fileSize:{$gte:1 }},{"fileName":0})
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "c4ca4238a0b923820dcc509a6f75849b", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
>
> db.demo.find({fileSize:{$gte:1 }},{"fileName":0})
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "c4ca4238a0b923820dcc509a6f75849b", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
> db.demo.find({fileSize:{$gte:1,$lt:0 }},{"fileName":0})
> db.demo.find({fileSize:{$gte:1,$lt:1 }},{"fileName":0})
> db.demo.find({type:{$ne : 1}})
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661"), "abstractFileId" : "2c46051d7ad8435d90854f93388a7f3f", "createTime" : "2019-09-06T02:55:00.705Z", "updateTime" : "2019-09-06T02:55:00.705Z", "appId" : "", "fileId" : "7708cd240102499fb2ea76be4ed30b8b", "groupId" : "2a35477e083d40f38e9c49ee6821264c", "fileName" : "测试.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 0, "fileLastModified" : 1567738500562, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "d41d8cd98f00b204e9800998ecf8427e", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2019-09-06T02:55:00.705Z", "path" : "/2a35477e083d40f38e9c49ee6821264c/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a028c540cc5e47fad2662"), "abstractFileId" : "88f5184ea0d04ba4a6db7585bf968ef9", "createTime" : "2018-11-15T09:01:27.593Z", "updateTime" : "2018-11-15T09:01:27.593Z", "fileName" : "5ad3da678c4041f08f4d049be5e540ed", "fileSize" : 0, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : false, "type" : "0", "shareSign" : 1, "userSign" : "0230fa68b633442dac7f8c2ee01b4265", "effectiveDate" : "2018-11-15T09:01:27.593Z", "path" : null, "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "fileName" : "test1.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "c4ca4238a0b923820dcc509a6f75849b", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
> db.demo.find({type:{$ne : 0}})
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661"), "abstractFileId" : "2c46051d7ad8435d90854f93388a7f3f", "createTime" : "2019-09-06T02:55:00.705Z", "updateTime" : "2019-09-06T02:55:00.705Z", "appId" : "", "fileId" : "7708cd240102499fb2ea76be4ed30b8b", "groupId" : "2a35477e083d40f38e9c49ee6821264c", "fileName" : "测试.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 0, "fileLastModified" : 1567738500562, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "d41d8cd98f00b204e9800998ecf8427e", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2019-09-06T02:55:00.705Z", "path" : "/2a35477e083d40f38e9c49ee6821264c/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a028c540cc5e47fad2662"), "abstractFileId" : "88f5184ea0d04ba4a6db7585bf968ef9", "createTime" : "2018-11-15T09:01:27.593Z", "updateTime" : "2018-11-15T09:01:27.593Z", "fileName" : "5ad3da678c4041f08f4d049be5e540ed", "fileSize" : 0, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : false, "type" : "0", "shareSign" : 1, "userSign" : "0230fa68b633442dac7f8c2ee01b4265", "effectiveDate" : "2018-11-15T09:01:27.593Z", "path" : null, "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "fileName" : "test1.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "c4ca4238a0b923820dcc509a6f75849b", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
可使用$in操作符指定一组可能的匹配值。SQL中对应的操作符为IN.下面的代码将使用Sin操作符从media集合中获取数据:
> db.demo.find({fileName:{$ne : 'test1.txt'}})
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661"), "abstractFileId" : "2c46051d7ad8435d90854f93388a7f3f", "createTime" : "2019-09-06T02:55:00.705Z", "updateTime" : "2019-09-06T02:55:00.705Z", "appId" : "", "fileId" : "7708cd240102499fb2ea76be4ed30b8b", "groupId" : "2a35477e083d40f38e9c49ee6821264c", "fileName" : "测试.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 0, "fileLastModified" : 1567738500562, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "d41d8cd98f00b204e9800998ecf8427e", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2019-09-06T02:55:00.705Z", "path" : "/2a35477e083d40f38e9c49ee6821264c/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a028c540cc5e47fad2662"), "abstractFileId" : "88f5184ea0d04ba4a6db7585bf968ef9", "createTime" : "2018-11-15T09:01:27.593Z", "updateTime" : "2018-11-15T09:01:27.593Z", "fileName" : "5ad3da678c4041f08f4d049be5e540ed", "fileSize" : 0, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : false, "type" : "0", "shareSign" : 1, "userSign" : "0230fa68b633442dac7f8c2ee01b4265", "effectiveDate" : "2018-11-15T09:01:27.593Z", "path" : null, "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "fileExtend" : { }, "version_" : 1 }
> db.demo.find({fileName:{$in : 'test1.txt'}})
Error: error: {
"ok" : 0,
"errmsg" : "$in needs an array",
"code" : 2,
"codeName" : "BadValue"
}
> db.demo.find({fileName:{$in : ['test1.txt']}})
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "fileName" : "test1.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "c4ca4238a0b923820dcc509a6f75849b", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
>
$nin与$in类似,不过它将搜索特定字段的值不在特定数组列表中的文档:
> db.demo.find({fileName:{$nin : ['test1.txt']}})
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661"), "abstractFileId" : "2c46051d7ad8435d90854f93388a7f3f", "createTime" : "2019-09-06T02:55:00.705Z", "updateTime" : "2019-09-06T02:55:00.705Z", "appId" : "", "fileId" : "7708cd240102499fb2ea76be4ed30b8b", "groupId" : "2a35477e083d40f38e9c49ee6821264c", "fileName" : "测试.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 0, "fileLastModified" : 1567738500562, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "d41d8cd98f00b204e9800998ecf8427e", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2019-09-06T02:55:00.705Z", "path" : "/2a35477e083d40f38e9c49ee6821264c/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a028c540cc5e47fad2662"), "abstractFileId" : "88f5184ea0d04ba4a6db7585bf968ef9", "createTime" : "2018-11-15T09:01:27.593Z", "updateTime" : "2018-11-15T09:01:27.593Z", "fileName" : "5ad3da678c4041f08f4d049be5e540ed", "fileSize" : 0, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : false, "type" : "0", "shareSign" : 1, "userSign" : "0230fa68b633442dac7f8c2ee01b4265", "effectiveDate" : "2018-11-15T09:01:27.593Z", "path" : null, "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "fileExtend" : { }, "version_" : 1 }
>
> db.demo.find({fileName:{$nin : ['test1.txt',"5ad3da678c4041f08f4d049be5e540ed"]}})
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661"), "abstractFileId" : "2c46051d7ad8435d90854f93388a7f3f", "createTime" : "2019-09-06T02:55:00.705Z", "updateTime" : "2019-09-06T02:55:00.705Z", "appId" : "", "fileId" : "7708cd240102499fb2ea76be4ed30b8b", "groupId" : "2a35477e083d40f38e9c49ee6821264c", "fileName" : "测试.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 0, "fileLastModified" : 1567738500562, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "d41d8cd98f00b204e9800998ecf8427e", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2019-09-06T02:55:00.705Z", "path" : "/2a35477e083d40f38e9c49ee6821264c/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
> db.demo.find({fileName:{$all : ['test1.txt',"5ad3da678c4041f08f4d049be5e540ed"]}})
>
- 5,匹配文档中的所有属性操作符$all的工作方式也与$in类似。不过, $all要求文档的所有属性都匹配,而$in操作符只要求文档中的一个属性匹配即可。
- 6,在文档中搜索多个表达式在单个查询中可以使用$or操作符搜索多个表达式,它将返回满足其中任何一个条件的文档。与$in操作符不同, $or允许同时指定键和值,而不是只指定值:
可以获取集合中除某些符合特定条件的文档之外的所有文档。注意,所选字段有许多潜在的值时, $ne可能带来很负面的性能影响。
> db.demo.find({"fileName":"test1.txt"},{"fileSize":{$slice:2}})
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "fileName" : "test1.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "c4ca4238a0b923820dcc509a6f75849b", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
> db.demo.find({"fileName":"test1.txt"},{"fileSize":{$slice:1}})
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "fileName" : "test1.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "c4ca4238a0b923820dcc509a6f75849b", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
>
使用$slice投射可把数组字段限制为匹配结果的一个数组子集。如果希望通过限制结果元素的数目来节省带宽,那么该操作符非常有用。通过该操作符还可以获取结果中每页的n项数据,该特性通常称为分页。
该操作符接受两个参数:
第一个参数表示将要返回数据项的总数;
第二个参数是可选的,如果使用了该参数,那么第一个参数将用于定义偏移,第二个参数用于定义限制。参数limit也可以使用负值,从数组尾部而不是数组开头开始返回数据项。
通过使用$mod操作符可以搜索由奇数或偶数组成的特定数据。该操作符将把目标值除以2,并检查该运算的余数是否为0,通过这种方式只提供偶数结果。
> db.demo.find({fileSize:{$mod:[2,0]}},{"md5":0})
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661"), "abstractFileId" : "2c46051d7ad8435d90854f93388a7f3f", "createTime" : "2019-09-06T02:55:00.705Z", "updateTime" : "2019-09-06T02:55:00.705Z", "appId" : "", "fileId" : "7708cd240102499fb2ea76be4ed30b8b", "groupId" : "2a35477e083d40f38e9c49ee6821264c", "fileName" : "测试.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 0, "fileLastModified" : 1567738500562, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2019-09-06T02:55:00.705Z", "path" : "/2a35477e083d40f38e9c49ee6821264c/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a028c540cc5e47fad2662"), "abstractFileId" : "88f5184ea0d04ba4a6db7585bf968ef9", "createTime" : "2018-11-15T09:01:27.593Z", "updateTime" : "2018-11-15T09:01:27.593Z", "fileName" : "5ad3da678c4041f08f4d049be5e540ed", "fileSize" : 0, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : false, "type" : "0", "shareSign" : 1, "userSign" : "0230fa68b633442dac7f8c2ee01b4265", "effectiveDate" : "2018-11-15T09:01:27.593Z", "path" : null, "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "fileExtend" : { }, "version_" : 1 }
>
8、搜索奇数/偶数通过使用$mod操作符可以搜索由奇数或偶数组成的特定数据。该操作符将把目标值除以2,并检查该运算的余数是否为0,通过这种方式只提供偶数结果。
> db.demo.find({fileSize:{$mod:[2,1]}},{"md5":0})
{ "_id" : ObjectId("5f9a02c7540cc5e47fad2663"), "abstractFileId" : "c24caae23e8640d7866f5ba3868002c3", "createTime" : "2020-02-03T06:00:57.007Z", "updateTime" : "2020-02-03T06:00:57.007Z", "appId" : "", "fileId" : "8718cc3d96f24fcdad234f8ed139c6d0", "groupId" : "2e77af3e3ba047d09ecd7d5e79c3d6f0", "fileName" : "test1.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 1, "fileLastModified" : 1580709656815, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2020-02-03T06:00:57.007Z", "path" : "/2e77af3e3ba047d09ecd7d5e79c3d6f0/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
> db.demo.find({fileSize:{$mod:[2,0]}},{"md5":0})
{ "_id" : ObjectId("5f9a01fc540cc5e47fad2661"), "abstractFileId" : "2c46051d7ad8435d90854f93388a7f3f", "createTime" : "2019-09-06T02:55:00.705Z", "updateTime" : "2019-09-06T02:55:00.705Z", "appId" : "", "fileId" : "7708cd240102499fb2ea76be4ed30b8b", "groupId" : "2a35477e083d40f38e9c49ee6821264c", "fileName" : "测试.txt", "extension" : ".txt", "contentType" : "text/plain", "fileSize" : 0, "fileLastModified" : 1567738500562, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "reviseUserSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : "2019-09-06T02:55:00.705Z", "path" : "/2a35477e083d40f38e9c49ee6821264c/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 1 }
{ "_id" : ObjectId("5f9a028c540cc5e47fad2662"), "abstractFileId" : "88f5184ea0d04ba4a6db7585bf968ef9", "createTime" : "2018-11-15T09:01:27.593Z", "updateTime" : "2018-11-15T09:01:27.593Z", "fileName" : "5ad3da678c4041f08f4d049be5e540ed", "fileSize" : 0, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : false, "type" : "0", "shareSign" : 1, "userSign" : "0230fa68b633442dac7f8c2ee01b4265", "effectiveDate" : "2018-11-15T09:01:27.593Z", "path" : null, "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "fileExtend" : { }, "version_" : 1 }
>
- 9,使用$size过滤结果通过操作符$size可以过滤出文档中数组大小符合条件的结果。例如,可以使用该操作符搜索只含有两首歌曲的CD:
4.3.7使用正则表达式
前缀表达式是一种正则表达式,它以一个左锚点("\A")或插入符号(^)开头,其后是几个字符(例如: "Matrix" )。
记住,不分大小写( "i" )的正则表达式查询,其性能很糟,因为使用这类查询时,需要执行大量的收缩。
> db.demo0808.find()
{ "_id" : "fff4fbc598024ac7935554c9d15bad30", "abstractFileId" : "82c1f30957b54533823341e3eff3feb0", "createTime" : "2020-07-15T01:25:25.469Z", "updateTime" : "2020-07-15T01:25:25.469Z", "fileName" : "其它报告", "fileSize" : 0, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : false, "type" : "0", "shareSign" : 1, "userSign" : "admin", "effectiveDate" : "2020-07-15T01:25:25.469Z", "path" : null, "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "fileExtend" : { }, "version_" : 1 }
{ "_id" : "fff2fa7ccce24bc782b7b5ead015392d", "abstractFileId" : "d0149c523fd04ec5a34cc21122638219", "createTime" : ISODate("2019-01-15T07:53:48.255Z"), "updateTime" : ISODate("2019-01-15T07:53:48.255Z"), "fileName" : "e18048c3dce643afb3559a345c1d4f9b", "fileSize" : NumberLong(0), "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : false, "type" : "0", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : ISODate("2019-01-15T07:53:48.255Z"), "path" : null, "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "fileExtend" : { }, "version_" : 1 }
> db.demo0808.find({fileName:/^其 */i})
{ "_id" : "fff4fbc598024ac7935554c9d15bad30", "abstractFileId" : "82c1f30957b54533823341e3eff3feb0", "createTime" : "2020-07-15T01:25:25.469Z", "updateTime" : "2020-07-15T01:25:25.469Z", "fileName" : "其它报告", "fileSize" : 0, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : false, "type" : "0", "shareSign" : 1, "userSign" : "admin", "effectiveDate" : "2020-07-15T01:25:25.469Z", "path" : null, "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "fileExtend" : { }, "version_" : 1 }
4.4更新数据
4.4.1使用updateo更新
在MongoDB中可以使用update()函数执行数据更新操作。该函数接受3个主要参数: criteria,objNew和options.
- 参数criteria可用于指定一个查询,该查询选择要更新的目标记录。
- 使用obijNew参数指定更新信息,也可以使用操作符来完成。
- 参数options用于指定更新文档时的选项,它的可选值有:upsert和 multi。
- 通过选项upsert可以指定该更新是否为upsert操作-它将告诉MongoDB,如果数据存在就更新,否则创建数据。
- 通过选项multi可以指定是否应该更新所有匹配的文档,或者只更新第一个文档(默认行为)。
> db.demo0808.updateOne({"fileName":"0808更新测试"},{$set:{"fileName":"测试.ppt"}},{upsert:true})
{
"acknowledged" : true,
"matchedCount" : 0,
"modifiedCount" : 0,
"upsertedId" : ObjectId("5fa491d83a95673bfe69d218")
}
> db.demo0808.find({"fileName":"0808更新测试"})
> db.demo0808.find({"fileName":"测试.ppt"})
{ "_id" : "ffa8fdfaa113446f88fd0a07eaed08ef", "abstractFileId" : "d2cf8d5393c449f58c587545d9444776", "createTime" : "2020-07-15T03:14:13.816Z", "updateTime" : "2020-07-15T03:14:13.816Z", "appId" : "", "fileId" : "03bd715060e245d9805e4f66d2618f12", "groupId" : "c1fa6fe5730748faa38ebc9d0275655d", "fileName" : "测试.ppt", "extension" : ".ppt", "contentType" : "application/vnd.ms-powerpoint", "fileSize" : 0, "fileLastModified" : 1567129291341, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "d41d8cd98f00b204e9800998ecf8427e", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "admin", "reviseUserSign" : "admin", "effectiveDate" : "2020-07-15T03:14:13.816Z", "path" : "/a19adc16bbd84f47b7741bbf45932603/0/技经资料/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 2 }
{ "_id" : ObjectId("5fa48fa23a95673bfe69d204"), "fileName" : "测试.ppt" }
{ "_id" : ObjectId("5fa491d83a95673bfe69d218"), "fileName" : "测试.ppt" }
> db.demo0808.find()
{ "_id" : "fff4fbc598024ac7935554c9d15bad30" }
{ "_id" : "fff2fa7ccce24bc782b7b5ead015392d", "abstractFileId" : "d0149c523fd04ec5a34cc21122638219", "createTime" : ISODate("2019-01-15T07:53:48.255Z"), "updateTime" : ISODate("2019-01-15T07:53:48.255Z"), "fileName" : "e18048c3dce643afb3559a345c1d4f9b", "fileSize" : NumberLong(0), "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "useGridFS" : false, "type" : "0", "shareSign" : 1, "userSign" : "d6af1ad234a54c02a0cf35f577326590", "effectiveDate" : ISODate("2019-01-15T07:53:48.255Z"), "path" : null, "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "fileExtend" : { }, "version_" : 1 }
{ "_id" : "ffa8fdfaa113446f88fd0a07eaed08ef", "abstractFileId" : "d2cf8d5393c449f58c587545d9444776", "createTime" : "2020-07-15T03:14:13.816Z", "updateTime" : "2020-07-15T03:14:13.816Z", "appId" : "", "fileId" : "03bd715060e245d9805e4f66d2618f12", "groupId" : "c1fa6fe5730748faa38ebc9d0275655d", "fileName" : "测试.ppt", "extension" : ".ppt", "contentType" : "application/vnd.ms-powerpoint", "fileSize" : 0, "fileLastModified" : 1567129291341, "thumbnailWH" : "0x0", "thumbnailPos" : "", "compressRate" : "0", "md5" : "d41d8cd98f00b204e9800998ecf8427e", "useGridFS" : true, "targetField" : "", "targetTable" : "", "remark" : "", "type" : "1", "shareSign" : 1, "userSign" : "admin", "reviseUserSign" : "admin", "effectiveDate" : "2020-07-15T03:14:13.816Z", "path" : "/a19adc16bbd84f47b7741bbf45932603/0/技经资料/", "lock_state" : "0", "fileState" : 1, "tenantId" : "0001", "extend" : { "filestate" : "", "fileversions" : "" }, "fileExtend" : { }, "version_" : 2 }
{ "_id" : ObjectId("5fa48fa23a95673bfe69d204"), "fileName" : "测试.ppt" }
{ "_id" : ObjectId("5fa491d83a95673bfe69d218"), "fileName" : "测试.ppt" }
4.4.2使用save()命令实现upsert
还可以使用save)命令执行upsert.为实现该操作,可指定_id值;可手动或自动添加该值.
如果不指定_id值, save()命令将认为它是一个插入操作,并将文档添加到集合中使用save)命令的主要优势是:
不需要指定使用update()命令时所需要使用的upsert参数。
> db.demo0817.save({_id:"5fb070b276e329b5bf255752"},{"id":"2134"})
WriteResult({
"nMatched" : 0,
"nUpserted" : 1,
"nModified" : 0,
"_id" : "5fb070b276e329b5bf255752"
})
> db.demo0817.find()
{ "_id" : ObjectId("5fb070b276e329b5bf255752"), "id" : 23, "name" : "lirui" }
{ "_id" : ObjectId("5fb070ca76e329b5bf255753"), "id" : 2, "name" : "lsdirui" }
{ "_id" : "5fb070b276e329b5bf255752" }
> db.demo0817.save({id:"23"},{"name":"1111111111111"})
WriteResult({ "nInserted" : 1 })
> db.demo0817.find()
{ "_id" : ObjectId("5fb070b276e329b5bf255752"), "id" : 23, "name" : "lirui" }
{ "_id" : ObjectId("5fb070ca76e329b5bf255753"), "id" : 2, "name" : "lsdirui" }
{ "_id" : "5fb070b276e329b5bf255752" }
{ "_id" : ObjectId("5fb071c976e329b5bf255754"), "id" : "23" }
> db.demo0817.save({id:23},{"name":"1111111111111"})
WriteResult({ "nInserted" : 1 })
> db.demo0817.find()
{ "_id" : ObjectId("5fb070b276e329b5bf255752"), "id" : 23, "name" : "lirui" }
{ "_id" : ObjectId("5fb070ca76e329b5bf255753"), "id" : 2, "name" : "lsdirui" }
{ "_id" : "5fb070b276e329b5bf255752" }
{ "_id" : ObjectId("5fb071c976e329b5bf255754"), "id" : "23" }
{ "_id" : ObjectId("5fb071ec76e329b5bf255755"), "id" : 23 }
> db.demo0817.save({"_id":"5fb070b276e329b5bf255752",id:23},{"name":"1111111111111"})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.demo0817.find()
{ "_id" : ObjectId("5fb070b276e329b5bf255752"), "id" : 23, "name" : "lirui" }
{ "_id" : ObjectId("5fb070ca76e329b5bf255753"), "id" : 2, "name" : "lsdirui" }
{ "_id" : "5fb070b276e329b5bf255752", "id" : 23 }
{ "_id" : ObjectId("5fb071c976e329b5bf255754"), "id" : "23" }
{ "_id" : ObjectId("5fb071ec76e329b5bf255755"), "id" : 23 }
>
4.4.3 自动更新信息
可使用修改操作符以简单的方式对文档进行快速更新,不需要手动输入任何信息。例如,
> db.demo0817.find()
{ "_id" : ObjectId("5fb070b276e329b5bf255752"), "id" : 23, "name" : "lirui" }
{ "_id" : ObjectId("5fb070ca76e329b5bf255753"), "id" : 2, "name" : "lsdirui" }
{ "_id" : "5fb070b276e329b5bf255752", "id" : 23 }
{ "_id" : ObjectId("5fb071c976e329b5bf255754"), "id" : "23" }
{ "_id" : ObjectId("5fb071ec76e329b5bf255755"), "id" : 23 }
> db.demo0817.u
db.demo0817.unsetWriteConcern( db.demo0817.update( db.demo0817.updateMany( db.demo0817.updateOne(
> db.demo0817.updateOne({"name":"lirui"},{$inc:{"id":23}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.demo0817.find()
{ "_id" : ObjectId("5fb070b276e329b5bf255752"), "id" : 46, "name" : "lirui" }
{ "_id" : ObjectId("5fb070ca76e329b5bf255753"), "id" : 2, "name" : "lsdirui" }
{ "_id" : "5fb070b276e329b5bf255752", "id" : 23 }
{ "_id" : ObjectId("5fb071c976e329b5bf255754"), "id" : "23" }
{ "_id" : ObjectId("5fb071ec76e329b5bf255755"), "id" : 23 }
>
1,使用$inc增加值
操作符$inc可以为指定的键执行(原子)更新操作,如果字段存在,就将该值增加给定的增量。如果字段不存在,就创建该字段。
> db.demo0817.find({})
{ "_id" : ObjectId("5fb070b276e329b5bf255752"), "id" : 55555, "name" : "lirui" }
{ "_id" : ObjectId("5fb070ca76e329b5bf255753"), "id" : 2, "name" : "lsdirui" }
{ "_id" : "5fb070b276e329b5bf255752", "id" : 23 }
{ "_id" : ObjectId("5fb071c976e329b5bf255754"), "id" : "23" }
{ "_id" : ObjectId("5fb071ec76e329b5bf255755"), "id" : 23 }
> db.demo0817.updateOne({id:"23"},{$inc:{ids:4}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.demo0817.find({})
{ "_id" : ObjectId("5fb070b276e329b5bf255752"), "id" : 55555, "name" : "lirui" }
{ "_id" : ObjectId("5fb070ca76e329b5bf255753"), "id" : 2, "name" : "lsdirui" }
{ "_id" : "5fb070b276e329b5bf255752", "id" : 23 }
{ "_id" : ObjectId("5fb071c976e329b5bf255754"), "id" : "23", "ids" : 4 }
{ "_id" : ObjectId("5fb071ec76e329b5bf255755"), "id" : 23 }
> db.demo0817.updateOne({id:"23"},{$inc:{ids:4}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.demo0817.find({})
{ "_id" : ObjectId("5fb070b276e329b5bf255752"), "id" : 55555, "name" : "lirui" }
{ "_id" : ObjectId("5fb070ca76e329b5bf255753"), "id" : 2, "name" : "lsdirui" }
{ "_id" : "5fb070b276e329b5bf255752", "id" : 23 }
{ "_id" : ObjectId("5fb071c976e329b5bf255754"), "id" : "23", "ids" : 8 }
{ "_id" : ObjectId("5fb071ec76e329b5bf255755"), "id" : 23 }
>
2,设置字段值:$set:
可以使用$set操作符将某个字段设置为指定值
> db.demo0817.updateOne({"name":"lirui"},{$set:{"id":55555}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.demo0817.find()
{ "_id" : ObjectId("5fb070b276e329b5bf255752"), "id" : 55555, "name" : "lirui" }
{ "_id" : ObjectId("5fb070ca76e329b5bf255753"), "id" : 2, "name" : "lsdirui" }
{ "_id" : "5fb070b276e329b5bf255752", "id" : 23 }
{ "_id" : ObjectId("5fb071c976e329b5bf255754"), "id" : "23" }
{ "_id" : ObjectId("5fb071ec76e329b5bf255755"), "id" : 23 }
>
3,删除指定字段,使用$unset:
通过$unset操作符可以删除指定的字段,
4,在指定字段添加值,$push:
通过$push操作符可以在指定字段中添加某个值。如果该字段是个数组,那么该值将被添加到数组中。
如果该字段尚不存在,那么该字段的值将被设置为数组。如果该字段存在,但不是数组,将会抛出错误。
> db.date.updateOne({name:"liruiong"},{$push:{"name2":"234324"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.date.find()
{ "_id" : ObjectId("5fb06e7d432a096e6b86a978"), "name" : "liruiong", "name1" : "liruiklong1", "name2" : [ "234324" ] }
{ "_id" : ObjectId("5fb06e7f432a096e6b86a979"), "name" : "liruiong", "name1" : "liruiklong1" }
{ "_id" : ObjectId("5fb06e80432a096e6b86a97a"), "name" : "liruiong", "name1" : "liruiklong1" }
{ "_id" : ObjectId("5fb06e81432a096e6b86a97b"), "name" : "liruiong", "name1" : "liruiklong1" }
{ "_id" : ObjectId("5fb06e87432a096e6b86a97c"), "name" : "liruiondfgfdg", "name1" : "lirdfgfduiklong1" }
> db.date.updateOne({name:"liruiong"},{$set:{"name2":"1111111111234324"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.date.find()
{ "_id" : ObjectId("5fb06e7d432a096e6b86a978"), "name" : "liruiong", "name1" : "liruiklong1", "name2" : "1111111111234324" }
{ "_id" : ObjectId("5fb06e7f432a096e6b86a979"), "name" : "liruiong", "name1" : "liruiklong1" }
{ "_id" : ObjectId("5fb06e80432a096e6b86a97a"), "name" : "liruiong", "name1" : "liruiklong1" }
{ "_id" : ObjectId("5fb06e81432a096e6b86a97b"), "name" : "liruiong", "name1" : "liruiklong1" }
{ "_id" : ObjectId("5fb06e87432a096e6b86a97c"), "name" : "liruiondfgfdg", "name1" : "lirdfgfduiklong1" }
> db.date.updateOne({name:"liruiong"},{$unset:{"name2":"1111111111234324"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.date.find()
{ "_id" : ObjectId("5fb06e7d432a096e6b86a978"), "name" : "liruiong", "name1" : "liruiklong1" }
{ "_id" : ObjectId("5fb06e7f432a096e6b86a979"), "name" : "liruiong", "name1" : "liruiklong1" }
{ "_id" : ObjectId("5fb06e80432a096e6b86a97a"), "name" : "liruiong", "name1" : "liruiklong1" }
{ "_id" : ObjectId("5fb06e81432a096e6b86a97b"), "name" : "liruiong", "name1" : "liruiklong1" }
{ "_id" : ObjectId("5fb06e87432a096e6b86a97c"), "name" : "liruiondfgfdg", "name1" : "lirdfgfduiklong1" }
>
5,指定数组中的多个值,使用$push操作符可以将值添加到指定数组中,扩展指定元素中存储的数据。
如果希望在给定的数组中添加几个不同的值,可以使用可选的$each修改操作符.
> db.data.find()
{ "_id" : ObjectId("5fb06f09432a096e6b86a97d"), "name" : "kiruiong" }
{ "_id" : ObjectId("5fb06f2f432a096e6b86a97e"), "name" : "liruiong" }
{ "_id" : ObjectId("5fb1bb391f36a81a0fcca01e"), "name" : "sdf", "array" : [ "123", "qweq" ] }
> db.data.updateOne({"name":"sdf",{$push:"array":{$each:["456","ert"]}}}
... )
2020-11-16T07:37:14.751+0800 E QUERY [js] SyntaxError: invalid property id @(shell):1:32
> db.data.updateOne({"name":"sdf"},{$push:"array":{$each:["456","ert"]}}} )
2020-11-16T07:38:07.941+0800 E QUERY [js] SyntaxError: missing } after property list @(shell):1:47
> db.data.updateOne({"name":"sdf"},{$push:{"array":{$each:["456","ert"]}}} )
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.data.find()
{ "_id" : ObjectId("5fb06f09432a096e6b86a97d"), "name" : "kiruiong" }
{ "_id" : ObjectId("5fb06f2f432a096e6b86a97e"), "name" : "liruiong" }
{ "_id" : ObjectId("5fb1bb391f36a81a0fcca01e"), "name" : "sdf", "array" : [ "123", "qweq", "456", "ert" ] }
>
6,使用$addToSet向数组中添加数据
操作符$addToSet是另一个可用于向数组中添加数据的命令。
不过,只有数据不存在的时候,该操作符才能将数据添加到数组中。
它的工作方式与$push不同。操作符$addToSet默认将接受一个参数。不过,在使用$addToSet时,可以使用$each操作符指定额外的参数。
> db.data.find()
{ "_id" : ObjectId("5fb06f09432a096e6b86a97d"), "name" : "kiruiong" }
{ "_id" : ObjectId("5fb06f2f432a096e6b86a97e"), "name" : "liruiong" }
{ "_id" : ObjectId("5fb1bb391f36a81a0fcca01e"), "name" : "sdf", "array" : [ "123", "qweq", "456", "ert", "55555" ] }
> db.data.updateOne({"name":"sdf"},{$addToSet:{"array":"55555"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 0 }
> db.data.find()
{ "_id" : ObjectId("5fb06f09432a096e6b86a97d"), "name" : "kiruiong" }
{ "_id" : ObjectId("5fb06f2f432a096e6b86a97e"), "name" : "liruiong" }
{ "_id" : ObjectId("5fb1bb391f36a81a0fcca01e"), "name" : "sdf", "array" : [ "123", "qweq", "456", "ert", "55555" ] }
> db.data.updateOne({"name":"sdf"},{$addToSet:{"array":{$each:["55555","66666","7777"]}})
... )
2020-11-16T07:47:25.584+0800 E QUERY [js] SyntaxError: missing } after property list @(shell):1:86
> db.data.updateOne({"name":"sdf"},{$addToSet:{"array":{$each:["55555","66666","7777"]}}}) )
2020-11-16T07:47:30.102+0800 E QUERY [js] SyntaxError: missing ; before statement @(shell):1:89
> db.data.updateOne({"name":"sdf"},{$addToSet:{"array":{$each:["55555","66666","7777"]}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.data.find()
{ "_id" : ObjectId("5fb06f09432a096e6b86a97d"), "name" : "kiruiong" }
{ "_id" : ObjectId("5fb06f2f432a096e6b86a97e"), "name" : "liruiong" }
{ "_id" : ObjectId("5fb1bb391f36a81a0fcca01e"), "name" : "sdf", "array" : [ "123", "qweq", "456", "ert", "55555", "66666", "7777" ] }
>
4.4.4从数组中删除元素
MongoDB中还包含了几种从数组中删除元素的方法,包括$pop, $pull和$pullAll.
操作符$pop可从数组中删除单个元素。
该操作符允许删除数组中的第一个或最后一个元素,具体取决于传入的参数。
{ "_id" : ObjectId("5fb1bb391f36a81a0fcca01e"), "name" : "sdf", "array" : [ "123", "qweq", "456", "ert", "55555", "66666", "7777" ] }
> db.data.updateOne({name:"sdf"},{$pop:{array:1}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.data.find({name:'sdf'})
{ "_id" : ObjectId("5fb1bb391f36a81a0fcca01e"), "name" : "sdf", "array" : [ "123", "qweq", "456", "ert", "55555", "66666" ] }
> db.data.updateOne({name:"sdf"},{$pop:{array:-1}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.data.find({name:'sdf'})
{ "_id" : ObjectId("5fb1bb391f36a81a0fcca01e"), "name" : "sdf", "array" : [ "qweq", "456", "ert", "55555", "66666" ] }
>
将传入的数值改为-2或-1000不会改变被移除的元素,只要使用的是负数,就会移除第一个教将移除最后一个元素,使用数字0也可以移除教组的最后一个元素。
1,删除所有指定值通过使用$pull操作符可以从数组中删除所有指定值。
2,删除数组中的多个元素,还可以从数组中删除多个含有不同值的元素。操作符$pullAll可以完成该操作。该操作符将接受一个希望移除元素的数组
> db.data.find({name:'sdf'})
{ "_id" : ObjectId("5fb1bb391f36a81a0fcca01e"), "name" : "sdf", "array" : [ "qweq", "456", "ert", "55555", "66666" ] }
> db.data.updateOne({name:"sdf"},{$pull:{array:"456"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.data.find({name:'sdf'})
{ "_id" : ObjectId("5fb1bb391f36a81a0fcca01e"), "name" : "sdf", "array" : [ "qweq", "ert", "55555", "66666" ] }
> db.data.updateOne({name:"sdf"},{$pullAll:{array:["ert","55555"]}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.data.find({name:'sdf'})
{ "_id" : ObjectId("5fb1bb391f36a81a0fcca01e"), "name" : "sdf", "array" : [ "qweq", "66666" ] }
>
4.4.5指定匹配数组的位置
可以在查询中使用$操作符指定查询中匹配数组元素的位置。该操作符可用于在搜索到一个数组元素之后,对它进行数据操作。
4.4.6原子操作
MongoDB支持针对单个文档的原子操作。
原子操作是一组可以结合在一起使用的操作,它们对于系统的其他部分来说就像单个操作一样。这组操作产生的结果可能是正面的也可能是负面的。
如果一组操作满足下面的条件,就可以称它们为原子操作;
- 其他进程无法获得修改的结果,除非整组操作都已经完成。
- 如果其中一个操作失败,整组操作(整个原子操作)都将失败,并全部回滚,数据将被恢复至运行原子操作之前的状态。
执行原子操作时的标准行为是锁定数据,不允许其他查询访问。不过,出于多种原因,MongoDB并不支持锁或复杂的事务:
- 在分片环境中分布式锁是昂贵并且缓慢的.MongoDB的目标是轻量并且快速,所以昂贵和缓慢的操作违反了它的原则。
- MongoDB开发者不喜欢死锁。在他们看来,系统最好是简单并且可预测的。
- MongoDB被设计用于处理实时问题。当执行一个操作需要锁定大量数据时,它将会停止一些轻量级查询的执行。该操作同样违背了MongoDB要求快速的目标。
MongoDB包含几种更新操作符(如之前所述),它们都可以原子操作的方式更新元素:
- $set:设置特定值。
- $unset:删除特定值。
- $inc:将某个值增大特定的量
- $push:向数组中添加值。
- $pull:从现有数组中删除一个或多个值。
- $pullAll:从现有数组中删除些值
使用Update if Current方法另一个原子更新元素的策略是使用Update if Current(如果数据目前仍未改变就更新)方法。
该方法有3个步骤:
- (1)从文档中取得对象。
- (2)在本地修改对象(使用之前提到的操作)。
- (3)发送更新请求来更新对象值,假定当前值仍然匹配之前取得的旧值。
这被称为ABA问题。在目前的场景中,似乎不可能出现这个问题,但在多用户环境中,许多应用都在同时处理数据,这就可能是一个明显的问题。为避免这个问题,可以使用下面的方法:
- 在更新的查询表达式中使用完整的对象,而不是只使用id和comments.by字段。
- 使用$set更新重要的字段。即使其他字段已经改变,也不会受该字段的影响。
- 在对象中添加一个版本变量,并在每次更新时增加它的值。
- 如有可能,请使用$操作符,而不是Update-if-Current序列操作。
MongoDB不支持在单个操作中以原子方式更新多个文档,相反,可使用嵌套对象来实现单个文档中的原子操作
4.4.7以原子方式修改和返回文档
还可以通过执行findAndModify命令来实现对文档的原子操作、该命令将修改并返回文档。·它将接受3个主要操作符:
- <query>用于指定目标文档,
- <sort>用于对多个匹配文档进行排序,
- <opertions>用于指定希望执行的操作
> db.data.find()
> db.data.insertOne({"name":"123",names:[12,23,34,45,56]}
... )
{
"acknowledged" : true,
"insertedId" : ObjectId("5fb312b909225b04f961dce0")
}
> db.data.find()
{ "_id" : ObjectId("5fb312b909225b04f961dce0"), "name" : "123", "names" : [ 12, 23, 34, 45, 56 ] }
>
增删改查操作:
> db.data.findAndModify({query:{"name":"123"},sort:{"name":-1},update:{$set:{"name":"345"}}})
{
"_id" : ObjectId("5fb3133e09225b04f961dce1"),
"name" : "123",
"names" : [
12,
23,
34,
45,
56
]
}
> db.data.find()
{ "_id" : ObjectId("5fb3133e09225b04f961dce1"), "name" : "345", "names" : [ 12, 23, 34, 45, 56 ] }
> db.data.findAndModify({query:{"name":"123"},sort:{"name":-1},update:{$pop:{"names":1}}})
null
> db.data.find()
{ "_id" : ObjectId("5fb3133e09225b04f961dce1"), "name" : "345", "names" : [ 12, 23, 34, 45, 56 ] }
> db.data.findAndModify({query:{"name":"345"},sort:{"name":-1},update:{$pop:{"names":1}}})
{
"_id" : ObjectId("5fb3133e09225b04f961dce1"),
"name" : "345",
"names" : [
12,
23,
34,
45,
56
]
}
> db.data.findAndModify({query:{"name":"345"},sort:{"name":-1},update:{$pop:{"names":-1}}})
{
"_id" : ObjectId("5fb3133e09225b04f961dce1"),
"name" : "345",
"names" : [
12,
23,
34,
45
]
}
> db.data.findAndModify({query:{"name":"345"},sort:{"name":-1},update:{$pop:{"names":-1}},new:true})
{
"_id" : ObjectId("5fb3133e09225b04f961dce1"),
"name" : "345",
"names" : [
34,
45
]
}
> db.data.find()
{ "_id" : ObjectId("5fb3133e09225b04f961dce1"), "name" : "345", "names" : [ 34, 45 ] }
>
4.5批处理数据
MongoDB还允许批量执行写入操作。
通过这种方式,可首先定义数据集,再一次写入它们。
批量写入操作只能处理单一集合,可以用于插入、更新或删除数据。
在批量写入数据之前,首先需要告诉MongoDB如何写入这些数据:有序还是无序。
- 以有·序方式执行操作时, MongoDB会按顺序执行操作的列表。也就是说,如果在处理一个写入操作时发生错误,就不处理剩下的操作。
- 使用无序写入操作时, MongoDB以并行方式执行操作。如果在处理一个写入操作时发生错误, MongoDB将继续处理剩余的写入操作
4.5.1执行批处理
以有序方式批量插入数据,如果发生一个错误,操作就停止。要使用initializeOrderedBulkOpo)函列表,如下所示:
这个使用书里的insertOne()不可用。也不知什么原因,可能是版本问题。
> var bulk = db.data.initializeOrderedBulkOp();
> bulk.insertOne({"name":"12"})
2020-11-18T08:05:55.898+0800 E QUERY [js] TypeError: bulk.insertOne is not a function :
@(shell):1:1
> bulk.insert({"name":"12"})
> bulk.insert({"name":"12"})
> bulk.execute()
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 2,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})
> var bulk = db.data.initializeOrderedBulkOp();
> bulk.insertOne({"name":"34"})
2020-11-18T08:07:47.893+0800 E QUERY [js] TypeError: bulk.insertOne is not a function :
@(shell):1:1
> bulk.insert({"name":"34"})
> bulk.execute()
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 1,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})
集合中以有序方式批量插入数据,如果发生一个错误,操作就停止。首先需要使用initializeOrderedBulkOp()函数,初始化有序列表,
列表最多可以包含1000个操作,列表超过这个极限时, MongoDB会自动分割列表,把它们放在几个包含1000个操作的组中。
4.5.2评估输出
要处理操作列表,可使用execute()命令, 一旦使用execute()命令执行了批操作,就能够审查执行的写入操作。 为审查通过execute()执行的写入操作,可以使用getOperations)命令,如下所示:
> bulk.getOperations();
[
{
"originalZeroIndex" : 0,
"batchType" : 1,
"operations" : [
{
"_id" : ObjectId("5fb465db12238826dfee33cd"),
"name" : "34"
}
]
}
]
>
返回的数组包含operations键下处理的所有数据, batchType键表示执行的操作类型。在这里,它的值是1,表示项插入到集合中。表4-2描述了操作的类型及其对应的batchType值。
在无序列表中处理各种类型的操作时, MongoDB会将这些操作按类型(插入、更新、删除·分组,来提高性能,因此,应确保应用不依赖操作执行顺序,有序列表的操作只会组合相同类型的连续操作,所以它们仍是按顺序处理的。
4.6重命名集合
可以使用renameCollections()函数重命名现有的集合。下面演示了如何使用这个简单的函数
> db.data.renameCollection("xi0820")
{ "ok" : 1 }
>
4.7删除数据
该语句将删除一个匹配的文档。使用deleteOnet)函数时,集合中符合条件的其他文档不会删除。为了删除多个符合条件的文档,可改用deleteManyo函数。
> db.da.find()
{ "_id" : ObjectId("5fb3133e09225b04f961dce1"), "name" : "345", "names" : [ 34, 45 ] }
{ "_id" : ObjectId("5fb4658212238826dfee33cb"), "name" : "12" }
{ "_id" : ObjectId("5fb4658212238826dfee33cc"), "name" : "12" }
> db.da.deleteOne({"name":"12"})
{ "acknowledged" : true, "deletedCount" : 1 }
> db.da.find()
{ "_id" : ObjectId("5fb3133e09225b04f961dce1"), "name" : "345", "names" : [ 34, 45 ] }
{ "_id" : ObjectId("5fb4658212238826dfee33cc"), "name" : "12" }
> db.da.insertOne({"name":"12"})
{
"acknowledged" : true,
"insertedId" : ObjectId("5fb4692f12238826dfee33ce")
}
> db.da.deleteMany({"name":"12"})
{ "acknowledged" : true, "deletedCount" : 2 }
> db.da.find()
{ "_id" : ObjectId("5fb3133e09225b04f961dce1"), "name" : "345", "names" : [ 34, 45 ] }
>
在删除文档时,需要记住:对该文档的任何引用都将保留在数据库中。出于该原因,一定·要保证同时删除或更新这些引用;否则,这些引用在执行时将返回null.
如果希望删除整个集合,可以使用drop()或removed()函数。
removed()比drop0)慢许多,因为所有索引都以这种方式保存。
如果需要删除集合中的所有数据和索引, drop()会比较快。
函数dropo()将返回真或假,取决于该操作是否成功执行。同样,如果希望从MongoDB中删除整个数据库,可以使用droplDatabase()函数。
4.8引用数据库
4.8.1手动引用数据
在手动引用数据时,可将另一个文档中的id存储在该文档中(通过完整的ID或更简单的常用条目),
> db.da.find()
{ "_id" : ObjectId("5fb3133e09225b04f961dce1"), "name" : "345", "names" : [ 34, 45 ] }
> show collections
da
> db
data
> db.das.insertOne({"_id":"name"})
{ "acknowledged" : true, "insertedId" : "name" }
> db.das.find()
{ "_id" : "name" }
> db.da.insertOne({"name":"5456"})
{
"acknowledged" : true,
"insertedId" : ObjectId("5fb489675b922d10058af273")
}
> var name = db.da.findOne()
> db.das.findOne({_id:name.name})
null
> db.das.findOne({_id:name.name,"ll":[12,234,34]})
null
> db.das.insertOne({_id:name.name,"ll":[12,234,34]})
{ "acknowledged" : true, "insertedId" : "345" }
> var name = db.da.findOne()
> db.das.findOne({_id:name.name,"ll":[12,234,34]})
{ "_id" : "345", "ll" : [ 12, 234, 34 ] }
> db.das.findOne({_id:name.name})
{ "_id" : "345", "ll" : [ 12, 234, 34 ] }
> db.das.find({_id:name.name})
{ "_id" : "345", "ll" : [ 12, 234, 34 ] }
>
4.8.2便用DBRefl用数据
DBRef标准提供了在文档之间引用数据的更正式规范。
用DBRef替代手动引用的主要原因是,引用中文档所在的集合可能发生变化。
所以,如果引用的一直都是相同的集合,那么手动引用数据也可以。使用DBRef可以将数据库引用存储为标准的嵌入对象(JSONBSON),使用一种标准方式代表引用,意味着驱动和数据框架可以添加辅助方法,以标准的方法操作引用。添加DBRef引用值的语法如下所示:
{$ref:<collectionname>,$id:<id value>[, $db : <database name>]}
save和insert的区别,save可以实现回显,而insert不可以。
> apress = ({"id":123,"name":"liruilong"})
{ "id" : 123, "name" : "liruilong" }
> db.user.in
db.user.initializeOrderedBulkOp( db.user.insert( db.user.insertOne(
db.user.initializeUnorderedBulkOp( db.user.insertMany(
> db.user.insert(apress)
WriteResult({ "nInserted" : 1 })
> db.user.find()
{ "_id" : ObjectId("5fb5051d0fd11cad1d0a9363"), "id" : 123, "name" : "liruilong" }
> apress
{ "id" : 123, "name" : "liruilong" }
> apress = ({"id":123,"name":"liruilong"})
{ "id" : 123, "name" : "liruilong" }
> db.user.save(apress)
WriteResult({ "nInserted" : 1 })
> apress
{
"id" : 123,
"name" : "liruilong",
"_id" : ObjectId("5fb505610fd11cad1d0a9364")
}
> apress
{ "id" : 123, "name" : "liruilong" }
> apress = ({"id":123,"name":"liruilong"})
{ "id" : 123, "name" : "liruilong" }
> db.user.save(apress)
WriteResult({ "nInserted" : 1 })
> apress
{
"id" : 123,
"name" : "liruilong",
"_id" : ObjectId("5fb505610fd11cad1d0a9364")
}
> db.user1.save({uid:[new DBRef('user',apress._id)]})
WriteResult({ "nInserted" : 1 })
> db.user1.find()
{ "_id" : ObjectId("5fb506390fd11cad1d0a9365"), "uid" : [ DBRef("user", ObjectId("5fb505610fd11cad1d0a9364")) ] }
> db.user1.save({usid:{ $ref:'user',$id:_id)})
2020-11-18T19:35:08.583+0800 E QUERY [js] SyntaxError: missing } after property list @(shell):1:41
> db.user1.save({usid:{ $ref:'user',$id:"_id")})
2020-11-18T19:35:35.710+0800 E QUERY [js] SyntaxError: missing } after property list @(shell):1:43
> db.user1.save({usid:{ $ref:'user',$id:"_id"}})
WriteResult({ "nInserted" : 1 })
> db.user1.find()
{ "_id" : ObjectId("5fb506390fd11cad1d0a9365"), "uid" : [ DBRef("user", ObjectId("5fb505610fd11cad1d0a9364")) ] }
{ "_id" : ObjectId("5fb507180fd11cad1d0a9366"), "usid" : DBRef("user", "_id") }
> db.user1.save({usid:{ $ref:'user',$id:"name"}})
WriteResult({ "nInserted" : 1 })
> db.user1.find()
{ "_id" : ObjectId("5fb506390fd11cad1d0a9365"), "uid" : [ DBRef("user", ObjectId("5fb505610fd11cad1d0a9364")) ] }
{ "_id" : ObjectId("5fb507180fd11cad1d0a9366"), "usid" : DBRef("user", "_id") }
{ "_id" : ObjectId("5fb507650fd11cad1d0a9367"), "usid" : DBRef("user", "name") }
>
> db.user1.save({usid:[new DBRef('user','5fb505610fd11cad1d0a9364')]})
WriteResult({ "nInserted" : 1 })
> db.user1.find()
{ "_id" : ObjectId("5fb506390fd11cad1d0a9365"), "uid" : [ DBRef("user", ObjectId("5fb505610fd11cad1d0a9364")) ] }
{ "_id" : ObjectId("5fb507180fd11cad1d0a9366"), "usid" : DBRef("user", "_id") }
{ "_id" : ObjectId("5fb507650fd11cad1d0a9367"), "usid" : DBRef("user", "name") }
{ "_id" : ObjectId("5fb5084b0fd11cad1d0a9368"), "usid" : DBRef("user", "name") }
{ "_id" : ObjectId("5fb508fc0fd11cad1d0a9369"), "usid" : DBRef("user", "name") }
{ "_id" : ObjectId("5fb5099f0fd11cad1d0a936a"), "usid" : DBRef("user", "name") }
{ "_id" : ObjectId("5fb50a530fd11cad1d0a936b"), "usid" : [ DBRef("user", "5fb505610fd11cad1d0a9364") ] }
>
4.9使用与索引相关的函数
MongoDB中包含了许多可用于维护索引的函数;
接下来首先将使用Createlndex()函数创建索引。函数Createlndex()可以接受至少一个参数,该参数将指定文档中某个键的名字,用于构建索引。
> db.da.find()
{ "_id" : ObjectId("5fb48bd25b922d10058af274"), "name" : "132" }
{ "_id" : ObjectId("5fb48ebd5b922d10058af275"), "name" : "132" }
{ "_id" : ObjectId("5fb500450fd11cad1d0a935c"), "name" : "123" }
{ "_id" : ObjectId("5fb500a70fd11cad1d0a935d"), "name" : 67878 }
{ "_id" : ObjectId("5fb503c80fd11cad1d0a9361"), "names" : [ DBRef("da", undefined) ] }
{ "_id" : ObjectId("5fb503de0fd11cad1d0a9362"), "names" : [ DBRef("das", undefined) ] }
> db.da.createIndex({name:1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
> db.da.createIndex({name:-1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 2,
"numIndexesAfter" : 3,
"ok" : 1
}
>
该命令将确保基于media集合的所有文档的Title值创建出一个索引。行尼的:1指定了索引的方向, :1表示升序, :-1表示降序。
BSON允许在文档中存储完整的数组:能够在内嵌的键上创建索引
> db.da.insertOne({"name":"3434",names:[{"n1":"23"},{"n2":"n2323"}]})
{
"acknowledged" : true,
"insertedId" : ObjectId("5fb5a3a45227f075021a0f2e")
}
> db.da.createIndex({names.n1}:1})
2020-11-19T06:44:44.654+0800 E QUERY [js] SyntaxError: missing : after property id @(shell):1:24
> db.da.createIndex({names.n1:1})
2020-11-19T06:44:58.262+0800 E QUERY [js] SyntaxError: missing : after property id @(shell):1:24
> db.da.createIndex({"names.n1":1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 3,
"numIndexesAfter" : 4,
"ok" : 1
}
>
强制使用某个索引查询数据:
> db.da.ensureIndex({ISBN:1},{background:true});
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 4,
"numIndexesAfter" : 5,
"ok" : 1
}
> db.da.find({"name":"123"})
{ "_id" : ObjectId("5fb500450fd11cad1d0a935c"), "name" : "123" }
> db.da.ensureIndex({ISBN:1},{background:true});
{
"numIndexesBefore" : 5,
"numIndexesAfter" : 5,
"note" : "all indexes already exist",
"ok" : 1
}
> db.da.find({"name":"123"}).hint({"name":-1}).explain()
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "data.da",
"indexFilterSet" : false,
"parsedQuery" : {
"name" : {
"$eq" : "123"
}
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"name" : -1
},
"indexName" : "name_-1",
"isMultiKey" : false,
"multiKeyPaths" : {
"name" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"name" : [
"[\"123\", \"123\"]"
]
}
}
},
"rejectedPlans" : [ ]
},
"serverInfo" : {
"host" : "liruilong",
"port" : 27017,
"version" : "4.0.19",
"gitVersion" : "7e28f4296a04d858a2e3dd84a1e79c9ba59a9568"
},
"ok" : 1
}
限制查询匹配
> db.da.find().min("name":12).max({"name":3434})
2020-11-19T06:59:31.316+0800 E QUERY [js] SyntaxError: missing ) after argument list @(shell):1:23
> db.da.find().min("name":12).max({"name":334})
2020-11-19T07:00:09.009+0800 E QUERY [js] SyntaxError: missing ) after argument list @(shell):1:23
> db.da.find().min({"name":12}).max({"name":334})
> db.da.find().min({"name":-2}).max({"name":334})
第5章GridFS
5.1背景
开发者必须有权读写这些文件,并且要求为Web服务器赋予本地文件系统的写权限。但这将是系统管理员噩梦
--将文件读取到服务器只是处理它的第一阶段。数据库可以存储二进制文件;通常,这么做并不优雅。
MySQL还有一种特殊的列类型,称为BLOB. PostgreSQL要求使用特殊的存储过程存储这样的文件-数据并不存储在表中。
选择将数据写入磁盘除了安全问题,它还添加了另一个需要备份的目录必须保证该信息被复制到所有正确的服务器。
MongoDB强制要求文件的大小不得超过16MB.
5.2使用GridFS
GridFS由两部分组成。更具体地说,它由两个集合组成。
一个集合存储文件名和诸如大小这样的相关信息(称为元数据),
而另一个集合保存文件数据自身,以255KB为一块。
该规范将这两个集合分别称为files和chunks,默认情况下, files和chunks集合在fs名称空间中创建,但这可以修改。
如果希望存储不同类型的文件,那么修改默认名称空间的能力就非常有用了。
5.3开始使用命令行工具
[root@liruilong dict]# mongofiles
2020-11-19T07:12:55.791+0800 no command specified
2020-11-19T07:12:55.791+0800 try 'mongofiles --help' for more information
[root@liruilong dict]# mongofiles list
2020-11-19T07:13:31.293+0800 connected to: localhost
[root@liruilong dict]# ls
[root@liruilong dict]# dd if=/dev/urandom of=test.file bs=5MB count=1
1+0 records in
1+0 records out
5000000 bytes (5.0 MB) copied, 0.473715 s, 10.6 MB/s
[root@liruilong dict]# ls
test.file
[root@liruilong dict]# mongofiles put test.file
2020-11-19T07:16:30.292+0800 connected to: localhost
2020-11-19T07:16:30.341+0800 added file: test.file
[root@liruilong dict]# mongofiles list
2020-11-19T07:16:37.800+0800 connected to: localhost
test.file 5000000
[root@liruilong dict]#
5.3.1使用_id鍵
MongoDB中的每个文档都在id键中存储了一个唯标识符。如同MySQL的自增字段一样, id键并不需要直接使用,除非需要使用它获取特定的文件。
5.3.2使用文件名
MongoDB不能假设一致的文件名(甚至大小也相同)代表着相同的文件,因此,如果MongoDB更新已有的文件,那么极可能引起错误。当然,可使用id键更新某个特定的文件;
[root@liruilong dict]# mongofiles put test.file
2020-11-19T07:19:31.472+0800 connected to: localhost
2020-11-19T07:19:31.508+0800 added file: test.file
[root@liruilong dict]# mongofiles list
2020-11-19T07:19:36.992+0800 connected to: localhost
test.file 5000000
test.file 5000000
[root@liruilong dict]#
5.3.3文件的长度
默认情况下,块的大小为255KB,但如果愿意,可以将它修改为另一个值。为判断出一个文件占用了多少个块,就需要知道两个信息。
第一必须知道每个块的大小
第二必须知道文件大小,
这样才可以知道该文件占用了多少个块。你可能认为这并不重要。毕竟,如果现在有一个文件大小为1MB,块大小为255KB,那么如果希望从800KB的位置开始访问数据,就需要从第4块开始读取数据。然而你仍然需要知道该文件的总大小,
原因是:如果不知道文件的大小,就不能判断出到底有多少有效的块。在刚才的例子中,完全可能从1.26MB(第6块)开始访问数据,并且没有什么机制可以阻止你。这种情况下,第6块是不存在的,但如果没有文件大小信息,就无法知道这一点。
5.3.4使用块大小
命令put还将返回块的大小,,如果网站使用的是流式视频,那么可以将视频分成许多块,这样就可以轻松跳到指定视频的任意一部分。
如果现在有一个大文件,就必须返回整个文件,找到文件指定区域的起始点。有了GridFS,就可以在块级别取出所有数据。如果使用的是默认大小,那么可以从任何一个255KB块开始读取数据。当然,也可以指定实际希望读取的数据位(例如,只希望查看一个60分钟电影中的第5分钟),这是一个非常高效的系统, 255KB在大多数情况下也是一个非常好的块大小。
如果决定要修改它,应该有一个好的理由。并且不要忘记建立基准并测试自定义块大小的性能:理论上更好的系统却无法达到预期,这种情况并不少见。
注意:MongoDB文档有16MB的大小限制,因为GridFS只是标准MongoDB框架下存储文件的一种不同方式,所以它也受此限制,这就意味着不能创建大于16MB的块,这不会构成问题,因为GridFS的目的就在于缓解对大文件的需求,如果担心当前存储的大文件会生成太多的块文档,那么不用担心, 目前,在生产环境中已经有MongoDB系统在使用超过10亿个文档
> db.fs.files.find()
{ "_id" : ObjectId("5fb5b3155406f22e40b1c879"), "chunkSize" : 261120, "uploadDate" : ISODate("2020-11-18T23:49:41.772Z"), "length" : 10000000, "md5" : "c3b00a2b55f5884b8d905a5f0432f5cf", "filename" : "liruilong.txt" }
{ "_id" : ObjectId("5fb5b4c74ccc4a4cb0991399"), "uploadDate" : ISODate("2020-11-18T23:56:55.085Z"), "length" : NumberLong(8000000), "chunkSize" : 261120, "md5" : "1234334ab34f1a874921d7f4e41c62a6" }
>
5.3.5跟踪上传日期
uploadDate键的作用是:存储文件在MongoDB中创建的日期。这也表明files集合只是一个普通的MongoDB集合,它包含一些普通的文档。
这意味着可以在其中添加任何额外的键值对(如果需要的话),与使用任何其他集合的方式相同。
例如,考虑一个真实世界的应用,该应用需要存储从各种不同文件中提取出的文本内容。通过这种方式,可以执行一些额外的索引和搜索。为实现该任务,可以添加一个键filetext用于存储文本
5.3.6生成文件的哈希值
5.4查看MongoDB中的数据
> db.fs.files.find()
{ "_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "chunkSize" : 261120, "uploadDate" : ISODate("2020-11-18T23:16:30.345Z"), "length" : 5000000, "md5" : "f06177e0c67b2fd8ec560eb6576a2627", "filename" : "test.file" }
{ "_id" : ObjectId("5fb5ac035406f22db7cac2b2"), "chunkSize" : 261120, "uploadDate" : ISODate("2020-11-18T23:19:31.513Z"), "length" : 5000000, "md5" : "f06177e0c67b2fd8ec560eb6576a2627", "filename" : "test.file" }
> db.fs.chunks.find({},{"data":0});
{ "_id" : ObjectId("5fb5ab4e5406f22da28539d8"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 0 }
{ "_id" : ObjectId("5fb5ab4e5406f22da28539d9"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 1 }
{ "_id" : ObjectId("5fb5ab4e5406f22da28539da"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 2 }
{ "_id" : ObjectId("5fb5ab4e5406f22da28539db"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 3 }
{ "_id" : ObjectId("5fb5ab4e5406f22da28539dc"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 4 }
{ "_id" : ObjectId("5fb5ab4e5406f22da28539dd"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 5 }
{ "_id" : ObjectId("5fb5ab4e5406f22da28539de"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 6 }
{ "_id" : ObjectId("5fb5ab4e5406f22da28539e0"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 8 }
{ "_id" : ObjectId("5fb5ab4e5406f22da28539e1"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 9 }
{ "_id" : ObjectId("5fb5ab4e5406f22da28539df"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 7 }
{ "_id" : ObjectId("5fb5ab4e5406f22da28539e2"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 10 }
{ "_id" : ObjectId("5fb5ab4e5406f22da28539e3"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 11 }
{ "_id" : ObjectId("5fb5ab4e5406f22da28539e5"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 13 }
{ "_id" : ObjectId("5fb5ab4e5406f22da28539e6"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 14 }
{ "_id" : ObjectId("5fb5ab4e5406f22da28539e4"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 12 }
{ "_id" : ObjectId("5fb5ab4e5406f22da28539e7"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 15 }
{ "_id" : ObjectId("5fb5ab4e5406f22da28539e8"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 16 }
{ "_id" : ObjectId("5fb5ab4e5406f22da28539ea"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 18 }
{ "_id" : ObjectId("5fb5ab4e5406f22da28539eb"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 19 }
{ "_id" : ObjectId("5fb5ab4e5406f22da28539e9"), "files_id" : ObjectId("5fb5ab4e5406f22da28539d7"), "n" : 17 }
Type "it" for more
5.4.1使用搜索命令
[root@liruilong dict]# !dd
dd if=/dev/urandom of=test.file bs=5MB count=1
1+0 records in
1+0 records out
5000000 bytes (5.0 MB) copied, 0.469531 s, 10.6 MB/s
[root@liruilong dict]# dd if=/dev/urandom of=liruilong.txt bs=10MB count=1
1+0 records in
1+0 records out
10000000 bytes (10 MB) copied, 0.948001 s, 10.5 MB/s
[root@liruilong dict]# dd if=/dev/urandom of=sy.html bs=8MB count=1
1+0 records in
1+0 records out
8000000 bytes (8.0 MB) copied, 0.77031 s, 10.4 MB/s
[root@liruilong dict]# ls
liruilong.txt sy.html test.file
[root@liruilong dict]# mongofiles put liruilong.txt
2020-11-19T07:44:39.827+0800 connected to: localhost
2020-11-19T07:44:39.909+0800 added file: liruilong.txt
[root@liruilong dict]# mongofiles lisr
2020-11-19T07:44:54.908+0800 'lisr' is not a valid command
2020-11-19T07:44:54.908+0800 try 'mongofiles --help' for more information
[root@liruilong dict]# mongofiles list
2020-11-19T07:44:57.618+0800 connected to: localhost
test.file 5000000
test.file 5000000
liruilong.txt 10000000
[root@liruilong dict]# ls
liruilong.txt sy.html test.file
[root@liruilong dict]# mongofiles search test.file
2020-11-19T07:46:13.400+0800 connected to: localhost
test.file 5000000
test.file 5000000
[root@liruilong dict]# mongofiles search liruilong.txt
2020-11-19T07:46:19.775+0800 connected to: localhost
liruilong.txt 10000000
5.4.2删除
[root@liruilong dict]# mongofiles delete liruilong.txt
2020-11-19T07:46:54.800+0800 connected to: localhost
2020-11-19T07:46:54.804+0800 successfully deleted all instances of 'liruilong.txt' from GridFS
[root@liruilong dict]# mongofiles list
2020-11-19T07:47:08.137+0800 connected to: localhost
test.file 5000000
test.file 5000000
[root@liruilong dict]#
5.4.3从MongoDB中获取文件
[root@liruilong dict]# mongofiles delete test.file
2020-11-19T07:48:42.634+0800 connected to: localhost
2020-11-19T07:48:42.638+0800 successfully deleted all instances of 'test.file' from GridFS
[root@liruilong dict]# mongofiles list
2020-11-19T07:48:47.554+0800 connected to: localhost
[root@liruilong dict]#
[root@liruilong dict]# ls
liruilong.txt sy.html test.file
[root@liruilong dict]# mongofiles get liruilong.txt >sdf
2020-11-19T07:50:22.976+0800 connected to: localhost
2020-11-19T07:50:23.017+0800 finished writing to liruilong.txt
[root@liruilong dict]# ls
liruilong.txt sdf sy.html test.file
[root@liruilong dict]# ls -lh
total 22M
-rw-r--r-- 1 root root 9.6M Nov 19 07:50 liruilong.txt
-rw-r--r-- 1 root root 0 Nov 19 07:50 sdf
-rw-r--r-- 1 root root 7.7M Nov 19 07:44 sy.html
-rw-r--r-- 1 root root 4.8M Nov 19 07:43 test.file
[root@liruilong dict]#
5.4.4 mongofiles命令小结
5.5使用Python
5.5.1连接数据库
5.5.2访问单词
5.6在MongoDB中添加文件
[root@liruilong dict]# python
Python 2.7.5 (default, Apr 2 2020, 13:16:51)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from pymongo import MongoClient
>>> import gridfs
>>> fs = gridfs.GridFS(db)
>>> with open("sy.html") as sunyue:
... uid = fs.put(sunyue)
...
>>> uid
ObjectId('5fb5b4c74ccc4a4cb0991399')
>>>
有两个有用的参数可与put命令结合使用, 别是filename和content type.
可以看出,通过这两个参数可以外别设置文件名和文件的内容类型,从磁盘中直接加载文件时这是非常有用"的,
,在处理通过网络接收到或者在内存中生成的文件时,这种方式更有用,因为在这些情况下,通过这种方式可使用与文件类似的语义,但不需要真正在磁盘上创建文件。
5.7从GridFS中读取文件
new = fs.get(uid)
>>> for work in new:
... pring(work)
...
5.8删除文件
第7章Python和MongoDB
7.1在Python中使用文档
7.2使用PyMongo模块
7.3连接和断开
>>> from pymongo import MongoClient
>>> c = MongoClient()
>>> db = c.inventory
>>> db
Database(MongoClient(host=['localhost:27017'], document_class=dict, tz_aware=False, connect=True), u'inventory')
>>> collentions = db.da
>>>
7.4插入数据
>>> item = {"name":"liruilong","age":25}
File "<stdin>", line 1
item = {"name":"liruilong","age":25}
^
SyntaxError: invalid syntax
>>> item = {"name":"liruilong","age":25}
>>> demo.insert_one(item)
<pymongo.results.InsertOneResult object at 0x7f495e16c3b0>
>>> items = [{"name":"yibiguwo","age":26},{"name":"xiaoming","age":25}]
>>> demo.insert_one(items)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python2.7/site-packages/pymongo/collection.py", line 689, in insert_one
common.validate_is_document_type("document", document)
File "/usr/lib64/python2.7/site-packages/pymongo/common.py", line 483, in validate_is_document_type
"collections.MutableMapping" % (option,))
TypeError: document must be an instance of dict, bson.son.SON, bson.raw_bson.RawBSONDocument, or a type that inherits from collections.MutableMapping
>>> demo.insert_many(items)
<pymongo.results.InsertManyResult object at 0x7f495e16cab8>
>>>
7.5搜索数据
>>> demo.find_one()
{u'age': 25, u'_id': ObjectId('5fb677086ef8c819ab101afb'), u'name': u'liruilong'}
>>> demo.find_one({"name":"liruilong"})
{u'age': 25, u'_id': ObjectId('5fb677086ef8c819ab101afb'), u'name': u'liruilong'}
>>> demo.find_one({"name":"liruilong"},fields={"_id":False})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python2.7/site-packages/pymongo/collection.py", line 1272, in find_one
cursor = self.find(filter, *args, **kwargs)
File "/usr/lib64/python2.7/site-packages/pymongo/collection.py", line 1460, in find
return Cursor(self, *args, **kwargs)
TypeError: __init__() got an unexpected keyword argument 'fields'
>>> demo.find_one({"name":"liruilong"},fields={"_id":False})
7.5.1搜索单个文档
7.5.2搜索多个文档
7.5.3使用点操作符
7.5.4返回字段查询
>>> for doc in demo.find():
... doc
...
{u'age': 25, u'_id': ObjectId('5fb677086ef8c819ab101afb'), u'name': u'liruilong'}
{u'age': 26, u'_id': ObjectId('5fb6779a6ef8c819ab101afc'), u'name': u'yibiguwo'}
{u'age': 25, u'_id': ObjectId('5fb6779a6ef8c819ab101afd'), u'name': u'xiaoming'}
>>> for doc in demo.find({"name":"liruilong"},Projection={"name":True}):
... doc
...
7.5.6聚集查询
7.5.7使用hintof定索引
7.5.8使用条件操作符重定义查询
7.5.9使用正则表达式执行搜索
第9章数据库管理
9.1使用管理工具
9.1.1 mongo-MongoDB控制台
9.1.2使用第三方管理工具
mongo是一个基于JavaScript的命令行控制台工具,它类似于主流关系数据库所提供的许多查询工具。
不过,mongo有自己的独特之处:可以直接运行用JavaScript编写的与MongoDB数据库交互的程序。通过该控制台可以使用JavaScript与MongoDB进行交互,并可将这些脚本保存为js文件,以便在需要的时候运行。
事实上, mongo控制台中的许多内置命令都是用JavaScript编写的。可将在命令shell中输入的许多命令添加到一个扩展名为js的文件中,
启动shell时,以添加该文件名到命令行或者从shell 中使用load()函数的方式运行它们, shell将执行文件的内容,然后退出。这在运行一组重复命令时非常有用。
9.2备份MongoDB服务器
MongoDB的备份工具被称为mongodump,该工具作为标准发行版本的一部分发布.7例将在运行的MongoDB服务器上执行一个简单备份,并将文件保存在指定的磁盘目录中:
9.2.1创建备份
[root@liruilong ~]# cd ~
[root@liruilong ~]# mkdir testmongobackup
[root@liruilong ~]# cd testmongobackup/
[root@liruilong testmongobackup]# mongod
mongod mongodump
[root@liruilong testmongobackup]# mongodump
2020-11-19T22:28:42.894+0800 writing admin.system.version to
2020-11-19T22:28:42.895+0800 done dumping admin.system.version (1 document)
2020-11-19T22:28:42.895+0800 writing test.fs.chunks to
2020-11-19T22:28:42.895+0800 writing data.da to
2020-11-19T22:28:42.895+0800 writing data.user1 to
2020-11-19T22:28:42.895+0800 writing date.demo0817 to
2020-11-19T22:28:42.914+0800 done dumping data.da (7 documents)
...
[root@liruilong testmongobackup]# ls
dump
[root@liruilong testmongobackup]# cd ~/testmongobackup/
[root@liruilong testmongobackup]# mongorestore --drop
2020-11-19T22:31:24.726+0800 using default 'dump' directory
2020-11-19T22:31:24.726+0800 preparing collections to restore from
2020-11-19T22:31:24.736+0800 reading metadata for test.fs.chunks from dump/test/fs.chunks.metadata.json
2020-11-19T22:31:24.739+0800 reading metadata for date.data from dump/date/data.metadata.json
2020-11-19T22:31:24.742+0800 reading metadata for data.user1 from
....
[root@liruilong testmongobackup]# ls
dump
选项-drop告诉mongorestore工具,在恢复集合之前先丢弃现有的数据。最终,备份数据将替换数据库现有的数据。
如果不使用-drop选项,被恢复的数据将被追加到每个集合的尾部,这将导致出现重复的数据。下面认真检查一下该例到底完成了什么工作。
默认情况下, mongodump工具将使用默认端口连接到本地数据库,并将所有数据库和集合相关的数据抓取出来,存储在预定义的文件夹结构中。
mongodump工具在写入备份文件之前,不会清空输出目录中的内容,如果输出目录中已经具有某些数据,那么它们不会被删除,除非它们的名称正好与mongodump将要备份的文件名(collectionname.bson)相同、如果希望将多个集合的转储文件保存在同一目录中,那么这是一件好事;不过,
如果每次备份时都使用相同的目录但不清空,那么可能会引起问题。
9.2.2备份单个数据库
在相同的服务器上运行多个应用时,通常希望分别备份每个数据库,而不是和之前的样例,一样一次备份所有数据库。
mongodump工具提供了-d database_name选项,用于实现单个数据库的备份。mongodump工具将为它创建./dump文件夹;不过,该文件夹只包含单个数据库的所有备份文件。
[root@liruilong testmongobackup]# mongodump -d data
2020-11-19T22:42:03.395+0800 writing data.da to
2020-11-19T22:42:03.395+0800 writing data.user1 to
2020-11-19T22:42:03.395+0800 writing data.das to
2020-11-19T22:42:03.395+0800 writing data.user to
2020-11-19T22:42:03.396+0800 done dumping data.da (7 documents)
2020-11-19T22:42:03.396+0800 done dumping data.user1 (7 documents)
2020-11-19T22:42:03.397+0800 done dumping data.user (2 documents)
2020-11-19T22:42:03.397+0800 done dumping data.das (4 documents)
[root@liruilong testmongobackup]# ls
dump
[root@liruilong testmongobackup]# cd dump/
[root@liruilong dump]# ls
admin data DATA_RECOVERY date inventory test
[root@liruilong dump]#
9.2.3备份单个集合
[root@liruilong dump]# ls
admin data DATA_RECOVERY date inventory test
[root@liruilong dump]# mongodump -d data -c da
2020-11-19T22:43:42.972+0800 writing data.da to
2020-11-19T22:43:42.973+0800 done dumping data.da (7 documents)
[root@liruilong dump]# ls
admin data DATA_RECOVERY date dump inventory test
[root@liruilong dump]# cd dump/
[root@liruilong dump]# ls
data
[root@liruilong dump]# cd data/
[root@liruilong data]# ls
da.bson da.metadata.json
[root@liruilong data]# vim da.metadata.json
[root@liruilong data]#
9.3深入学习备份
[root@liruilong data]# mongodump --help
Usage:
mongodump <options>
Export the content of a running server into .bson files.
Specify a database with -d and a collection with -c to only dump that database or collection.
See http://docs.mongodb.org/manual/reference/program/mongodump/ for more information.
general options:
--help print usage
--version print the tool version and exit
verbosity options:
-v, --verbose=<level> more detailed log output (include multiple times for more verbosity, e.g. -vvvvv,
or specify a numeric value, e.g. --verbose=N)
--quiet hide all log output
connection options:
-h, --host=<hostname> mongodb host to connect to (setname/host1,host2 for replica sets)
--port=<por
- 使用该选项指定数据库转储文件的存放目录。默认情况下, mongodump工具将在当前目录中创建一个名为/dump的文件夹,并将转储文件保存在其中。通过使用-o/-out选项可以选择其他路径用于放置转储文件。
- --authenticationDatabase arg:
- 指定保存用户凭据的数据库。在未使用该选项的情况下,mongodump默认将使用由-db选项指定的数据库。
- -authenticationMechanism arg:
- 默认使用MongoDB的挑战/响应机制(SCRAM)SHAI身份验证机制。该命令用于将验证模式切换为MongoDB企业版的Kerberos验证。
9.4恢复单个数据库或集合
使用mongodump工具备份单个数据库或集合, mongorestore工具也可以实现相同的操作。如果备份目录中含有目标集合或数据库的备份文件,就可以使用mongorestore恢复该数据库或集合;并不需要恢复备份文件中的所有内容。如果愿意的话,可以单独恢复每个数据库和集合。
[root@liruilong data]# mongorestore --help
Usage:
mongorestore <options> <directory or file to restore>
Restore backups generated with mongodump to a running server.
Specify a database with -d to restore a single database from the target directory,
or use -d and -c to restore a single collection from a single .bson file.
See http://docs.mongodb.org/manual/reference/program/mongorestore/ for more information.
general options:
--help print usage
--version print the tool version and exit
verbosity options:
-v, --verbose=<level> more detailed log output (include multiple times for more verbosity, e.g. -vvvvv,
or specify a numeric value, e.g. --verbose=N)
--quiet hide all log output
- --drop:该选项将告诉mongorestore在恢复集合之前删除现有的集合。这将保证不会出现重复的数据。如果未使用该选项,被恢复的数据将被添加(插入)到目标集合中
- --noobjcheek: 该选项将告诉mongorestore忽略将对象插入目标集合之前的验证步骤。
9.4.1恢复单个数据库
9.4.2恢复单个集合
mongorestore
mongorestore -d data
mongorestore -d data -c da --drop
9.5自动备份
9.5.1使用本地数据存储
如果系统中具有大的备份驱动器或者可以通过NFS或SMB挂载一个外部文件系统,那么可以使用一个简单脚本在指定的目录中创建归档文件。下面的脚本很容易设置,只需要将脚本顶部的变量改为本地系统的路径即可:
[root@liruilong ~]# !sh
sh mongdb.sh
dumping Mongo Database all
2020-11-24T08:45:15.687+0800 writing admin.system.version to
2020-11-24T08:45:15.687+0800 done dumping admin.system.version (1 document)
2020-11-24T08:45:15.687+0800 writing READ_ME_TO_RECOVER_YOUR_DATA.README to
2020-11-24T08:45:15.688+0800 done dumping READ_ME_TO_RECOVER_YOUR_DATA.README (1 document)
Arcjiving Mong database to /root/backups/all/databases-20201124-0845.tgz
/root/backups/all
dump/
[root@liruilong ~]# cd /root/backups/all/
[root@liruilong all]# ls
databases-20201124-0844.tgz databases-20201124-0845.tgz databases-date
[root@liruilong all]# rm -rf databases-date
[root@liruilong all]# ls
databases-20201124-0844.tgz databases-20201124-0845.tgz
#!/bin/bash
####################################
MONGO_DBS=""
BACKUP_TMP=~/tmp
BACKUP_DEST=~/backups
MONGODUMP_BIN=/usr/bin/mongodump
#####################################
BACKUPFILE_DATE=`date +%Y%m%d-%H%M`
# _do_store_archive <Database> <Dump_dir> <Desc_Dir> <Dest_file>
function _do_stoer_archive {
echo $3
mkdir -p $3
cd $2
tar -cvzf $3/$4 dump
}
# do_backup <Database name>
function _do_backup {
UNIQ_DIR="$BACKUP_TMP/$1"`date "+%s"`
mkdir -p $UNIQ_DIR/dump
echo "dumping Mongo Database $1"
if [ "all" = "$1" ];then
$MONGODUMP_BIN -o $unIQ_DIR/dump
else
$MONGODUMP_BIN -d $1 -o $unIQ_DIR/dump
fi
KEY="databases-$BACKUPFILE_DATE.tgz"
echo "Arcjiving Mong database to $BACKUP_DEST/$1/$KEY"
DEST_DIR=$BACKUP_DEST/$1
_do_stoer_archive $1 $UNIQ_DIR $DEST_DIR $KEY
rm -rf $UNIQ_DIR
}
# check to see if indeividual databases have been specified. otherwise backup the whole server
# to "all"
if [ "" = "$MONGO_DBS" ];then
MONGO_DB="all"
_do_backup $MONGO_DB
else
for MONGO_DB in $MONGO_DBS; do
_do_backup $MONGO_DB
done
fi
MONGO_DBS
| 保持该变量为空,本地服务器上的所有数据库都将被备份。也可以在该变量中设置一个数据库的列表,用于备份指定的数据库("dbl db2 db3"))
|
BACKUP_TMP
| 将该变量设置为保存备份文件的临时目录。归档完成后,删除该目录中的临时数据。要选择一个与脚本相关的合适目录。例如,如果在自己的本地账户中使用脚本创建备份,·就使用目录~/tmp:如果在系统的cronjob中以系统账户运行该脚本,那么使用/mp.在Amazon EC2实例上,就应该使用/mntmp,这样可以保证该文件夹不会被创建在系统的根分区上(它的空间非常小)
|
BACKUP_DEST
| 该变量保存了备份文件的目标目录,所有其他文件夹都将在该文件夹下创建。同样,要选择一个与脚本相关的合适目录
|
TAR BIN
| 使用该变量设置tar二进制文件的全路径:"在终端窗口中输入which tar可获取此路径
|
MONGODUMP——BIN
|
|
当然,也需要安装该脚本。如果希望每天运行该脚本,那就将它添加到/etc/cron.daily中然后重启cron服务让它生效。这种方式在大多数Linux发行版本中都可以正常运行,例如UbuntuFedora, CentOS和Red Hat。
如果希望备份频率低一些,就将脚本移到/etc/cron.weekly或/etc/cron.monthly。对于更频繁的备份,还可以使用/etc/cron.hourly.
[root@liruilong etc]# ls cron.*
cron.deny
cron.d:
0hourly sysstat
cron.daily:
logrotate man-db.cron
cron.hourly:
0anacron
cron.monthly:
cron.weekly:
[root@liruilong etc]#
9.5.2使用远端数据存储(基于云)
下面讲解如何使用S3方式存储备份文件:不过,同样的规则也适用于任何其他机制。
下例使用的s3cmd工具(用Python编写)可从http://3tools.or获得。
[root@liruilong ~]# yum -y install python-pip
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
base | 3.6 kB 00:00:00
epel | 4.7 kB 00:00:00
extras | 2.9 kB 00:00:00
mysql-connectors-community | 2.5 kB 00:00:00
mysql-tools-community | 2.5 kB 00:00:00
mysql57-community | 2.5 kB 00:00:00
ngodb-org | 2.5 kB 00:00:00
updates | 2.9 kB 00:00:00
(1/3): epel/x86_64/updateinfo | 1.0 MB 00:00:00
(2/3): updates/7/x86_64/primary_db | 4.5 MB 00:00:00
(3/3): epel/x86_64/primary_db | 6.9 MB 00:00:00
Package python2-pip-8.1.2-12.el7.noarch already installed and latest version
Nothing to do
[root@liruilong ~]# pip install s3cmd
Collecting s3cmd
Downloading http://mirrors.aliyun.com/pypi/packages/26/44/19e08f69b2169003f7307565f19449d997895251c6a6566ce21d5d636435/s3cmd-2.1.0-py2.py3-none-any.whl (145kB)
100% |████████████████████████████████| 153kB 2.8MB/s
Collecting python-dateutil (from s3cmd)
Downloading http://mirrors.aliyun.com/pypi/packages/d4/70/d60450c3dd48ef87586924207ae8907090de0b306af2bce5d134d78615cb/python_dateutil-2.8.1-py2.py3-none-any.whl (227kB)
100% |████████████████████████████████| 235kB 94.6MB/s
Collecting python-magic (from s3cmd)
Downloading http://mirrors.aliyun.com/pypi/packages/59/77/c76dc35249df428ce2c38a3196e2b2e8f9d2f847a8ca1d4d7a3973c28601/python_magic-0.4.18-py2.py3-none-any.whl
Collecting six>=1.5 (from python-dateutil->s3cmd)
Downloading http://mirrors.aliyun.com/pypi/packages/ee/ff/48bde5c0f013094d729fe4b0316ba2a24774b3ff1c52d924a8a4cb04078a/six-1.15.0-py2.py3-none-any.whl
Installing collected packages: six, python-dateutil, python-magic, s3cmd
Successfully installed python-dateutil-2.8.1 python-magic-0.4.18 s3cmd-2.1.0 six-1.15.0
[root@liruilong ~]#
对于Fedora, CentOS和Red Hat,可从http:/s3tools.org获得yum包,然后使用yum安装它。
- 安装该包后,运行s3cmd-configure以设置Amazon S3凭据。
- 注意只需要提供两个密钥:AWSACCESS KEY和AWS SECRETACCESS KEY.
- s3cmd工具将创建一个包含了必需信息的配置文件: ~1.s3cfg.
9.6备份大数据库
通常备份大数据库的时间是非常长的,甚至可能需要数小时才能完成。在此期间,还需要将数据库维护在一致的状态,因此备份中不能出现在不同时间点复制的文件。
数据库备份系统有一个必杀技,就是时间点快照,它的速度非常快。快照完成的速度越快,数据库服务器需要被冻结的时间就越短。
9.6.1 使用隐藏的辅助服务器备份数据
执行大数据备份的一种技术是:
从隐藏的辅助服务器备份数据,在备份期间可以冻结该服务器。备份完成后,重启该辅助服务器,让它从应用的其他服务器获得最新数据。
在MongoDB中创建隐藏辅助服务器是非常简单的,并且可以使用MongoDB的复制机制来保证它与主服务器一致。它的配置也较容易(关于如何设置隐藏的辅助服务器请参阅第11章)。
9.6.2便用日志文件系统创建快照
许多现代的卷管理系统都有在任意时间点创建驱动状态快照的能力。
使用文件系统快照是为MongoDB实例创建备份中最快捷高效的方式。
如何将MongoDB服务器保持在一致的状态下,此时磁盘中的所有数据也应该处于一致的状态。
如何阻塞写入操作,这样接下来的数据修改就不会被写入磁盘中,而缓存在内存里。
通过快照可读取创建快照时驱动的准确状态。系统卷或文件系统管理器将保证磁盘上的所有数据块,在创建快照之后发生的修改都不会被写入原位置;这样可以保留所有用于读取的磁盘数据。通常,使用快照的过程如下:
- (1)创建快照。
- (2)从快照中复制数据或将快照恢复到另一个卷中,具体取决于你的卷管理器。
- (3)释放快照:这样将会释放所有预留的磁盘块,它们不需要再返回驱动器的空闲空间链中。
- (4)在服务器仍然运行时,备份所有的副本数据。
这种方式最棒的地方在于创建快照时,数据仍然可以继续读取。
支持该功能的卷管理器包括:
- Linux和LVM卷管理系统
- Sun ZFS
- Amazon EBS卷
- 使用卷影副本的Windows Server
大多数卷管理器都具有快速创建快照的能力,通常只需要数秒时间,即使是在数据量非常大的情况下。
此时卷管理器并未真正复制数据;相反,它们将在驱动中插入一个标签,从而可以读取创建快照时驱动的状态。,
一旦备份系统完成对驱动快照的读取,接下来就可以将那些发生过修改的旧数据块放入驱动的空闲空间链中(或文件系统所使用的任何一种标识空闲空间的方式)。
为使这种创建备份的方式高效,必须将MongoDB日志文件保存在同一设备上,或者使MongoDB将所有未完成的磁盘写入输出到磁盘,这样才可以创建快照。
- 强制MongoDB完成刷新的特性称为fsync;
- 阻塞写入的函数称为lock,
MongoDB具有同时执行这两个操作的能力,这样在fsync执行之后,就不会再有磁盘写入发生,直至锁被释放。通过将日志保存在同一设备上或者同时执行fysnc和lock,可以保证磁盘上数据库的镜像处于一致状态,并保证在完成快照之前它们仍然保持一致的状态。
> use admin
switched to db admin
> db.fsyncLock()
{
"info" : "now locked against writes, use db.fsyncUnlock() to unlock",
"lockCount" : NumberLong(1),
"seeAlso" : "http://dochub.mongodb.org/core/fsynccommand",
"ok" : 1
}
> db.currentOp
db.currentOP( db.currentOp(
> db.currentOp()
{
"inprog" : [
{
"host" : "liruilong:27017",
"desc" : "fsyncLockWorker",
"active" : true,
"currentOpTime" : "2020-11-25T07:56:07.459+0800",
.... ]
"fsyncLock" : true,
"info" : "use db.fsyncUnlock() to terminate the fsync write/snapshot lock",
"ok" : 1
}
>
使MongoDB进入fsync和lock状态db. fsyncLock ()
使用下面的命令可以检查锁的当前状态: db.currentop()
状态"fsyncLock": true表示MongoDB的fsync进程(负责将修改写入磁盘)正在阻塞写入操作。此时,就可以使用必要的命令通知卷管理器,创建MongoDB用于存储文件的文件夹的快照。一旦快照完成,就可以使用下面的命令释放锁
> db.fsyncUnlock()
{ "info" : "fsyncUnlock completed", "lockCount" : NumberLong(0), "ok" : 1 }
> db.currentOp()
{
"inprog" : [
{
"host" : "liruilong:27017",
"desc" : "conn802",
"connectionId" : 802,
"client" : "127.0.0.1:46156",
"appName" : "MongoDB Shell",
"clientMetadata" : {
"application" : {
"name" : "MongoDB Shell"
},
"driver" : {
"name" : "MongoDB Internal Client",
"version" : "4.0.19"
},
"os" : {
"type" : "Linux",
"name" : "CentOS Linux release 7.8.2003 (Core)",
"architecture" : "x86_64",
"version" : "Kernel 3.10.0-514.26.2.el7.x86_64"
}
},
"active" : true,
"currentOpTime" : "2020-11-25T07:59:54.560+0800",
"opid" : 4728964,
"lsid" : {
"id" : UUID("f25907c4-c6db-49c3-b1f7-9b79f9bff7d4"),
"uid" : BinData(0,"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=")
},
"secs_running" : NumberLong(0),
"microsecs_running" : NumberLong(133),
"op" : "command",
"ns" : "admin.$cmd.aggregate",
"command" : {
"currentOp" : 1,
"lsid" : {
"id" : UUID("f25907c4-c6db-49c3-b1f7-9b79f9bff7d4")
},
"$db" : "admin"
},
"numYields" : 0,
"locks" : {
},
"waitingForLock" : false,
"lockStats" : {
}
}
],
"ok" : 1
}
>
9.6.3使用卷管理器时的磁盘布局
某些卷管理器可以创建某个分区上子目录的快照,但大多数都无法做到,
最好将计划用于存储MongoDB数据的卷挂载到文件系统上一个合适的位置(例如/mnt/mongodb),并使用服务器配置选项将数据目录、配置文件和任何其他MongoDB相关的文件(例如日志)存储在该目录中。
9.7将数据导入MongoDB
MongoDB中包含了批量加载器mongoimport,用于将数据直接导入服务器的特定集合中;
它不同于mongorestore,因为mongorestore的目的在于从备份文件恢复MongoDB二进制数据。
mongoimport工具可加载以下三种文件格式的数据:
- CSV:在此种文件格式中,每行代表一个文档,字段之间由逗号分隔。
- TSV:该文件格式类似于CSV:不过,它使用Tab字符作为分隔符。该格式十分常见,因为它不要求对任何文本字符进行转义(除了换行符)。
- JSON:该文件格式每行都包含一块JSON,代表一个文档。与其他格式不同, JSON可以支持可变模式的文档。JSON是默认的输出格式。该工具的使用相当直观。它将接受一个使用了以上三种格式中任意一种格式的文件、一个字符串或含有一组列头的文件(这些组成了MongoDB文档的元素名),以及几个用于控制如何解释数据的服务器选项。
[root@liruilong ~]# mongoimport --help
Usage:
mongoimport <options> <file>
Import CSV, TSV or JSON data into MongoDB. If no file is provided, mongoimport reads from stdin.
See http://docs.mongodb.org/manual/reference/program/mongoimport/ for more information.
general options:
--help print usage
--version print the tool version and exit
verbosity options:
-v, --verbose=<level> more detailed log output (include multiple times for more
verbosity, e.g. -vvvvv, or specify a numeric value, e.g.
--verbose=N)
--quiet hide all log output
connection options:
-h, --host=<hostname> mongodb host to connect to (setname/host1,host2 for
replica sets)
--port=<port> server port (can also use --host
。。。。。。。。。。。。。。。。。。。。。。
- --headerline:使用文件的第一行作为字段名称列表。注意该选项只可用于CSV和TSV格式。
- --ignoreblanks:不导入任何空字段。如果字段为空,文档中将不会创建该元素;如果不使用该选项,那么文档中将创建一个使用了该列名的空元素。
- --drop:删除集合,并使用导入的数据重新创建该集合;否则,导入的数据将被追加到集合中
- -numlnsertionWorkers:要创建的插入操作的数量,用于插入文档。该数字越大,吞吐量就越大,耗费的资源就越多
- -jsonArray:允许导入/导出的数据有多个MongoDB文档,且在一个JSON数组中表示。使用mongoimport导入数据时还可以使用-d和-c选项指定数据库名和集合名,如下所示:
[root@liruilong ~]# mongoimport -d data -c da --type json --drop <demo.json
-bash: demo.json: No such file or directory
[root@liruilong ~]#
9.8从MongoDB导出数据
mongoexport用于从现有的MongoDB集合将数据导出到文件中。
这是将MongoDB实例中的数据导出成一种可由其他数据库或电子表格应用读取的文件格式的最好方式之一。
- -q:指定用于选择输出记录的查询。该查询可以是任何JSON查询字符串(但不是JavaScript查询字符串,因为它通常无法如预期一样工作),这些查询字符串应该可以通过使用db.collection.find()函数选择数据库中记录的一个子集。如果不指定该选项或将它的值设置为1,mongoexport工具将输出所有记录。
- -f:列出需要导出的数据库元素名。
[root@liruilong ~]# touch data.json
[root@liruilong ~]# mongoexport -d date -c da -q {} -f _id > data.json
2020-11-25T08:20:31.074+0800 connected to: localhost
2020-11-25T08:20:31.075+0800 exported 0 records
[root@liruilong ~]# cat data.json
[root@liruilong ~]#
9.9通过限制对 MongoDB 服务器的访问保护数据安全
MongoDB支持简单的基于角色的身份验证系统,通过该系统可以控制用户对数据库的访问以及他们被授予的访问级别。
默认MongoDB不使用任何身份验证方式。任何可以访问网络的人都可以连接到服务器并执行命令。
不过,可以在任何数据库中添加用户,这样就可以对MongoDB进行配置,使得在访问数据库时既要求有连接,还需要进行控制台验证。这是限制对admin函数访问的推荐方式。
9.10使用身份验证保护服务器
MongoDB支持基于角色的访问控制(RBAC)身份验证模型,其中包含预定义的系统角色和用户定义的定制角色。
MongoDB支持对每个数据库的访问进行单独控制,访问控制信息被存储在特有的system.users集合中。
对于希望访问两个数据库(例如, dbl和db2)的普通用户,他们的凭据和权限必须被同时添加到两个数据库中。
如果在不同数据库为同一用户分别创建了登录和访问权限,这些记录不会相互同步
任何添加到admin数据库中的用户,在所有数据库中都拥有相同的访问权限;不需要为这样的用户单独赋予权限。
9.10.1添加admin用户
添加admin用户非常简单,只需要切换到admin数据库,然后使用createUser()函数即可:
> use admin
switched to db admin
> db.createUser({user:"root",pwd:"root",roles:[{role:"readWrite",db:"admin"},{role:"userAdminAnyDatabase",db:"admin"}]})
Successfully added user: {
"user" : "root",
"roles" : [
{
"role" : "readWrite",
"db" : "admin"
},
{
"role" : "userAdminAnyDatabase",
"db" : "admin"
}
]
}
>
此时,只需要添加单个admin用户即可:一旦该用户定义成功,就可以使用该账户在admin数据库中添加其他admin用户,或在任何其他数据库中添加普通用户。
9.10.2启用身份验证身份验证
[root@liruilong ~]# systemctl restart mongod.service
[root@liruilong ~]#
[root@liruilong ~]# mongo
MongoDB shell version v4.0.20
connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("9097154c-aaac-4ba2-9116-ba26b4274635") }
MongoDB server version: 4.0.20
> show dbs
> use admin
switched to db admin
> show collections
Warning: unable to run listCollections, attempting to approximate collection names by parsing connectionStatus
> db.auth({"root","root"})
2020-08-29T17:52:38.452+0800 E QUERY [js] SyntaxError: missing : after property id @(shell):1:15
> db.auWarning: unable to run listCollections, attempting to approximate collection names by parsing connectionStatus
db.auth("root","root")
1
>
mongo控制台将会输出1(身份验证成功)或0(身份验证失败):
9.10.4 MongoDB用户角色
目前在MongoDB的权限框架中,用户可使用的角色有:
- read:允许用户读取指定的数据库。
- readWrite:授予用户对指定数据库的读写权限
- dbAdmin:允许用户在指定的数据库中执行管理功能,例如创建或删除索引、查看统计或访问system.profile集合。
- userAdmin:允许用户向system.users集合中写入内容。具有该权限的用户可在该数据库创建、删除和管理用户
- dbOwner: readWrite dbAdmin和userAdmin角色的组合。
- clusterManager:只在admin数据库中可用。为用户赋予针对整个集群的管理功能,不能访问数据功能
- clusterMonitor:只在admin数据库中可用。访问统计信息和收集统计信息的命令。hostManager:只在admin数据库中可用。管理和监控主机级别的服务。
- clusterAdmin:只在admin数据库中可用。为用户赋予所有分片和复制集相关函数的完全管理权限。也可以与clusterManager, clusterMonitor和hostManager一起使用。
- backup:只在admin数据库中可用。授予备份整个系统所需的最低访问权限。
- restore:只在admin数据库中可用。授予恢复整个系统所需的最低访问权限。
- readAnyDatabase:只在admin数据库中可用。为用户赋予所有数据库的读权限。
- readWriteAnyDatabase:只在admin数据库中可用。为用户赋予所有数据库的读写权限。
- userAdminAnyDatabase:只在admin数据库中可用。为用户赋予所有数据库的userAdmin权限。
- dbAdminAnyDatabase:只在admin数据库中可用。为用户赋予所有数据库的dbAdmin权限。
9.10.5修改用户凭据
> db.updateUser("liruilong",{roles:[{role:"dbAdmin",db:"demo"}]}
... )
> db.getUser()
2020-08-29T18:07:43.024+0800 E QUERY [js] Error: User name for getUser shell helper must be a string :
DB.prototype.getUser@src/mongo/shell/db.js:1735:1
@(shell):1:1
> db.getUsers()
[
{
"_id" : "demo.liruilong",
"userId" : UUID("311dfcaa-1fda-45f3-9bf4-dbc2c43a8f6f"),
"user" : "liruilong",
"db" : "demo",
"roles" : [
{
"role" : "dbAdmin",
"db" : "demo"
}
],
"mechanisms" : [
"SCRAM-SHA-1",
"SCRAM-SHA-256"
]
}
]
>
9.10.6添加只读用户
> db.createUser({user:"liruilong",pwd:"liruilong",roles:[{role:"read",db:"demo"}]})
Successfully added user: {
"user" : "liruilong",
"roles" : [
{
"role" : "read",
"db" : "demo"
}
]
}
9.10.7删除用户身份验证
> db.removeUser("liruilong")
WARNING: db.removeUser has been deprecated, please use db.dropUser instead
true
> db.getUsers()
[ ]
>
9.11管理服务器
作为管理员,必须保证MongoDB服务器的平稳和可靠运行。必须定期对服务器进行优化,从而使服务器达到最优性能,或对它们进行重新配置,以更好地匹配所使用的环境。为此,必须熟悉用于管理和控制服务器的大量函数。
9.11.1启动服务器
systemctl start mongod.service
systemctl restart mongod.service
# mongod.conf
# for documentation of all options, see:
# http://docs.mongodb.org/manual/reference/configuration-options/
# where to write logging data.
systemLog:
destination: file
logAppend: true
path: /var/log/mongodb/mongod.log
# Where and how to store data.
storage:
dbPath: /var/lib/mongo
journal:
enabled: true
# engine:
# mmapv1:
# wiredTiger:
# how the process runs
processManagement:
fork: true # fork and run in background
pidFilePath: /var/run/mongodb/mongod.pid # location of pidfile
timeZoneInfo: /usr/share/zoneinfo
# network interfaces
net:
port: 27017
bindIp: 0.0.0.0 # Enter 0.0.0.0,:: to bind to all IPv4 and IPv6 addresses or, alternatively, use the net.bindIpAll setting.
security:
authorization: enabled
#operationProfiling:
#replication:
#sharding:
## Enterprise-Only Options
#auditLog:
#snmp:
dbpath:表示MongoDB存储数据的位置:需要保证数据存储在一个快速存储卷上,并且它的大小要足以容纳数据库中的数据。
logpath:表示MongoDB存储日志的文件;标准路径是/var/logs/mongodb/mongodb.log:需要使用logrotate对日志进行轮转,防止出现日志填满服务器硬盘的情况。
logappend:将该选项设置为false, MongoDB在每次启动时都将清空日志文件。将该选项设置为true,所有的日志将被追加到现有日志文件的尾部。
auth:启用或禁用MongoDB服务器的身份验证模式;关于身份验证的更多信息,请参阅本章之前的讨论。
rest:启用或禁用MongoDB的rest接口。如果希望使用基于Web的状态显示链接来显示一些额外信息,就必须启用该接口,但在生产环境中不建议这么做,因为所有信息通过Mongo shell都可以获得。
9.11.2获得服务器版本
9.11.3获得服务器状态
> db.serverStatus()
{
"host" : "liruilong",
"version" : "4.0.20",
"process" : "mongod",
"pid" : NumberLong(5429),
"uptime" : 6,
"uptimeMillis" : NumberLong(5711),
"uptimeEstimate" : NumberLong(5),
"localTime" : ISODate("2020-08-29T10:20:45.675Z"),
"asserts" : {
"regular" : 0,
"warning" : 0,
"msg" : 0,
"user" : 1,
"rollovers" : 0
},
"connections" : {
"current" : 1,
"available" : 51199,
"totalCreated" : 1,
"active" : 1
},
9.11.4关闭服务器
systemctl stop mongod.service
9.12使用MongoDB日志文件
默认情况下, MongoDB将把所有日志都输出标准输出流中;使用下面的命令可以告诉MongoDB转换日志:
> db.adminCommand({logRotate:1})
{ "ok" : 1 }
9.13验证和修复数据
- 数据库服务器拒绝启动,表示数据文件已损坏。
- 在服务器日志文件中发现断言,或使用db.serverStatus)命令时发现断言数目很大。
- 查询结果很奇怪或出乎意料。
- 集合中的记录数目与预期不匹配。
9.13.1修复服务器
在启动服务器修复进程之前,必须注意,使用repair命令是一个代价高昂的操作,会耗费很长时间,并要求使用两倍于MongoDB数据文件大小的空间,
因为所有的数据都将被克隆到新的文件并重建,这本质上是对所有数据文件的重建。这是使用复制集的最好理由之一:如果需要将某个机器离线并修复,此时不需要完全停止复制集,也仍然可以处理客户端的请求。
为启动修复进程,手动启动服务器进程即可(如本章之前所述)。不过,此次需要在命令的尾部添加-repair选项,如下所示:
mongod --dbpath /data/db --repair
注意:使用mongod命令和--repair选项启动的服务器最终会退出,这是正常的;
为了正式启动服务器,只需要移除--repair选项并再次启动即可.
一旦修复进程结束,就可以正常启动服务器,然后从备份中恢复任何丢失的数据。
如果尝试修复一个大型数据库,那么驱动器上的磁盘空间可能不足,因为MongoDB需要在同一驱动器中创建数据库的副本作为数据源(参见之前样例中的目录..stmp repariDatabase o.).为处理这个潜在问题,
MongoDB修复工具提供了一个额外的命令行参数-repairPath.可以使用该参数指定一个具有足够空间的驱动器,用于保存修复过程中创建的临时文件,
如下所示:$ mongod-f /etc/mongodb.conf --repair --repairpath /mnt/bigdrive/tempdiz
9.13.2验证单个集合
> db
test
> db.demo.insert({})
WriteResult({ "nInserted" : 1 })
> db.demo.find()
{ "_id" : ObjectId("5f4a304c57d5f9b4e9705acd") }
> db.demo.ensureIndex({Author:1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
> db.demo.validate()
{
"ns" : "test.demo",
"nInvalidDocuments" : NumberLong(0),
"nrecords" : 1,
"nIndexes" : 2,
"keysPerIndex" : {
"_id_" : 1,
"Author_1" : 1
},
"valid" : true,
"warnings" : [
"Some checks omitted for speed. use {full:true} option to do more thorough scan."
],
"errors" : [ ],
"extraIndexEntries" : [ ],
"missingIndexEntries" : [ ],
"ok" : 1
}
>
9.13.3修复集合验证错误
修复集合索引错误
如果验证结果显示索引是损坏的,那么可以使用relndex()函数重建受影响集合的索引(这包· 括前台建立索引的过程,会阻塞对系统的访问),
> db.demo.reIndex()
{
"nIndexesWas" : 2,
"nIndexes" : 2,
"indexes" : [
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.demo"
},
{
"v" : 2,
"key" : {
"Author" : 1
},
"name" : "Author_1",
"ns" : "test.demo"
}
],
"ok" : 1
}
9.13.4修复集合的数据文件
修复数据库中所有数据文件的最好(也是最危险)的方式是:
使用服务器的-repair选项或shell中的db. repairDatabase)命令。后者将修复单个数据库中的所有集合文件,然后重建所有已定义的索引。
不过, repairDatabase()不适合在在线服务器上运行,因为它在重建数据文件时会阻塞对数据的所有请求。这将导致在数据库修复过程中,所有读取和写入操作都被阻塞。
> db.repairDatabase()
{ "ok" : 1 }
>
9.13.5压缩集合的数据文件
由于MongoDB内部分配数据文件的方式,因此可能会碰到“瑞士奶酪”这种情况,它意味着一小块空的存储空间被保留在磁盘数据结构中。这可能是一个问题,因为数据文件中可能有大量空间未被使用。使用修复功能重建整个数据结构可能能够解决这个问题,但也可能会带来其他不可预料的结果。而命令compact会在己有数据文件中为指定的集合整理并重组数据结构,使用默认的WiredTiger存储引擎会恢复磁盘空间,但不能用于旧MMAPV1存储引擎:
> db.runCommand({compact:"posts"})
{
"ok" : 0,
"errmsg" : "collection does not exist",
"code" : 26,
"codeName" : "NamespaceNotFound"
}
>
9.16使用MongoDB云管理器
到目前为止所讨论的统计信息都可以通过MongoDB云管理器服务(MongoDB Cloud ManagerService,以前称为MMS)获得,
云管理器是由MongoDB公司提供的免费监控服务。它提供了一个可安装在本地机器中的代理。一旦安装成功,就可以通过MMS Web页面添加正确的服务器,从而指示代理对它们进行监控。
一旦开始监控,就可以进入特定的主机,查看MongoDB实例的性能统计图。你可以监控MongoDB的所有信息,从单个MongoDB实例到复制集,乃至完整的分片集群(包括配置服务器和Mongos),
第10章优化
10.1优化服务器硬件以提高性能
10.2理解MongoDB的存储引擎
10.37解MMAPv1中MongoDB使用内存的方式
10.4理解WiredTiaer下MongoDB的内存使用方式
10.4.1 WiredTiger中的压缩
10.4.2选择正确的数据库服务器硬件
10.5评估查询性能
10.5.1 MongoDB分析器
10.5.2使用explain0分析特定的查询
10.5.3使用分析器和explain0优化查询
10.6管理索引
10.6.1显示索引
10.6.2创建简单的索引
10.6.3创建复合索马
10.7 Jesse Jiryu Davis的三步混合素引
10.7.1设置
10.7.2范围查询
10.7.3相等和范围查询
10.7.4题外话: MongoDB选择索引的方式
10.7.5相等、范围查询和排序
10.7.6*后的方法
10.8指定索引选项
10.8.1使用(background: true)在后台创建索引
10.8.2使用(unique: true)创建健索引
10.8.3使用(sparse: true)创建稀疏索引
第11章复制
11.1 MongoDB复制的目标
在所有特性中,复制可用于实现可扩展性、可持久性/可靠性和隔离性。
11.1.1改善可扩展性
- 提高冗余度:复制可以通过运行多个数据中心的方式提高冗余度。通过这种方式,保证每个数据中心都有一份数据的本地副本,这样应用就可以快速访问它们。用户可以连接到离它最近的数据中心,最小化延迟。
- 改善性能:在某些特定的情况下,复制可以帮助改善应用的性能。对于一个主要以数据库读取为主的大Web应用,如果希望在多个数据库服务器之间派发查询以提高并发度,就更是如此。对于使用各种不同工作集的查询负载来说也是这样,例如报表或聚集
11.1.2改善持久性/可靠性
复制通常用于防止硬件故障或数据库损坏,同时为备份和其他具有重要影响的维护活动提供灵活性
- 希望拥有数据库的一个副本,该副本将延迟运行。你可能希望保护自己避免应用中的缺陷,或者提供一种简单的机制,通过标出所有数据集的查询结果的不同,提供趋势信息.还可以为人为错误提供一个安全的环境,避免完全从备份恢复的需求。
- 希望拥有一个备份系统,以避免系统出现失败的情况。为避免由于系统故障所造成的影响,避免使用普通的备份模式进行长时间恢复,可以使用复制作为备份。
- 出于管理目的,希望拥有一个元余系统。使用复制之后,就可以在各个节点之间轮流执行备份或升级这样的管理任务。
11.1.3提供隔离性
对某些进程来说,如果在生成数据库中运行它们,将对数据库的性能或可用性造成巨大影啊。可以使用复制创建一个同步的副本,将进程从生成数据库隔离出来,
例如:希望运行报表或备份,而不希望影响生产系统的性能:维护一台隐藏的辅助复制服务器将可以帮助从报告系统中隔离出查询,并保证月末的报告不会延迟或影响正常操作。
11.2复制基础
在MongoDB中,复制集由一个主节点以及许多辅助或仲裁节点组成。复制集需要大量的主动成员才能维护主服务器。
因此最少应该有3个成员。通常的建议是有奇数个成员。。
为了避免“脑裂” (Split Brain)问题,也就是当网络出现问题时,有两台服务器成为主服务器的情况,
11.2.1主服务器的定义
在复制集的术语中,主服务器是在特定时间内复制集的数据来源,它是复制集中唯一可以·写入的节点,所有其他的节点都将从这里复制出它们的数据。主服务器由所有主动成员中的大多数投案产生,这被称为法定人数(quorum).
11.2.2辅助服务器的定义
辅助服务器成员是一个具有数据的非主服务器成员,它是一个可读取的节点,同时它将以尽可能接近 实时的方式从主服务器复制数据。默认情况下,如果连接到辅助服务器但不使用任何读取偏好,就不能执行读操作。
这是因为读取非主服务器时,如果复制过程中有延迟存在,读取的可能就是旧数据。
可以使用rs.slave0k0将当前连接设置为可从辅助服务器读取数据。或者如果使用的是某种驱动,那么也可以设置读取偏好,另外,辅助服务器可以使用复制链从一个服务器复制到另一个服务器,见后面的内容。
11.2.3仲裁服务器的定义.
仲裁服务器是一个不含有数据的节点,如果复制集中的主动成员数是偶数,它就用于提供额外的主动成员。它不会投出决定性的一票或者直接决定哪个节点是主服务器,但会参与并作为主动成员中的一员,决定哪个节点成为主服务器。
如前所述,仲裁服务器用于帮助避免“脑裂”问题。考虑图11-2所示的图表。有了站点A中的仲裁服务器,我们总是可以在某一边成功完成大多数服务器的投票选举。这意味着当网络出现问题时,不会出现两个主服务器。我们可以进一步增加元余性,在第3个站点C中添加一个仲裁服务器。这样如果站点A宕机,站点B和C仍然可以成功完成投票选举。通过以这种方式使用第3个站点,哪怕失去任何一个站点的连接,服务器都可以继续正常运行.
11.3深入学习oplog
简单地说, oplog(操作日志)就是一个固定大小的集合,保存了主服务器实例对数据库做出修改的记录, 目的是在辅助服务器上重做这些操作,保证数据库处于一致状态。服务器的每个成员都将维护自己的oplog,并且辅助服务器将查询主服务器(或者通过复制链进行其他数据更新的辅助服务器)的oplog,从而获得新条目,并应用到自己的数据库副本中。
oplog将为每个条目创建一个时间戳,通过这种方式,辅助服务器可以记录从上一次读取开始过去了多久,以及有多少oplog需要读取,如果终止辅助服务器并在较短的时间内重启它,它将从主服务器的oplog中获取在它离线的时间内所发生的所有修改。
因为具有一个无限大的oplog是不现实的,所以oplog通常具有固定的大小。可将oplog看成主服务器实例最近活动的窗口;如果窗口太小,那么记录中的某些操作在被应用到辅助服务器之前将丢失。如果当前实例的oplog尚未创建,那么使用-oplogSize启动选
11.4实现复制集
11.4.1创建复制集
11.4.2启动复制集成员
11.4.3向复制集中添加服务器
11.4.4添加仲裁服务器
11.4.5复制集链
11.4.6管理复制集
11.4.7为复制集成员配置选项
11.4.8从应用连接到复制集
第12章分片
分片(sharding)这种技术可将数据分散到多台机·器,但对于应用来说,仍然如同在使用单个数据库一样。分片非常适用于基于云的计算平台,由MongoDB实现的分片非常擅长以动态和负载敏感的方式自动调整规模,可在需要的时候增大容量,同时也可以减小容量。
12.1了解分片的需求
但随着网络的爆炸性增长,网站和访问者的数量也随之呈指数级增长。数量庞大的可用资源,迫使早期的Web先驱从使用简单的文档开始转向更复杂的动态页面,并将信息保存在不同的数据存储结构中。
搜索引擎开始在Web中爬网,并将今天数以亿计的链接和网页保存在数据库中。
这些发展推动了由内容管理系统管理和维护的数据集的发展,为便于访问它们,数据主要,存储在数据库中。与此同时,新的服务也在不断发展,它们所存储的不仅是文档和链接。音频、视频、事件和所有其他数据种类都开始进入这些大的数据存储中。
这个过程通常被称为“数据的工业化”,与19世纪主要发生于制造业的工业革命有诸多相似之处。最终,所有在Web中获得成功的公司都面临着一个问题:如何访问这些存储在庞大数据库中的数据。它们发现单个数据库每秒只能处理这么多查询,而网络和磁盘驱动器每秒也只能从服务器获得或发送这么多数据量。提供基于Web的服务的公司很快发现,它们的需求已经超出单个服务器、网络或驱动阵列的最大性能。
这种情况下,它们被迫将庞大的数据分割并分散开常见的解决方案是将这些庞大的数据块分割成小块数据,以便通过更可靠和快速的方式进行管理。与此同时,这些公司需要保持对整个数据集(保存在巨大的机器集群中)进行操作的能力。
12.2对数据进行水平和垂直分区
一种将数据分割到多个独立数据存储中的机制。这些数据存储既可以在本地(驻留在同一系统中),也可以在远端(分散在不同系统中),使用本地分区的动机是减少每个索引的大小和更新记录所需的I/O访问量。使用远程分区的动机是增大访问数据的带宽,通过使用更多RAM存储数据、避免磁盘访问或提供更多可用网络接口和磁盘1/0通道的方式来实现。
12.2.1对数据进行垂直分区
垂直分区的实现方式为:拆分列边界上的记录,并将各个部分存储在不同的表或集合中。可以认为,关系数据库通过按照一对一关系使用连接表构成的是本地垂直数据分区。
MongoDB并未使用这种形式的分区,因为它的记录结构(文档)并不适合整洁的行列模型。因此,几乎很难根据列边界将行清楚地分开.MongoDB还采用了嵌入文档,它并未直接提供在服务器上连接关联集合的能力(这些可以在应用中完成).
12.2.2对数据进行水平分区
水平分区是唯一可采用的方式,而分片就是各种流行水平分区的通用术语。通过分片,可将集合分割到多个服务器,从而改善包含大量文档的集合的性能。
当需要将用户记录的集合分割到一组服务器时,使用分片的一个简单样例是:将所有姓以A-G开头的人的所有记录保存在一台服务器上,将以H~M开头的人的所有记录保存在另一台·服务器上,依此类推。分割数据的规则被称分片键。简单来说,通过分片可将分片云当成单个完整的数据库使用,应用不需要关注数据是否被分散到多个机器。传统的分片实现要求应用积极参与决定特定的文档存储在哪台服务器上,这样才可以正确地发出请求。通常,需要将一个库绑定到应用,该库将负责存储和查询分片数据集中的数据。
MongoDB使用一种唯一的方法用于分片,由MongoS路径进程管理数据的分割,并将请求路由到必需的分片服务器。如果查询需要访问多个分片中的数据, Mongos将管理从多个分片获取数据并将数据合并成单个游标的过程。相较于其他特性,正是这个特性帮助MongoDB获得了“云数据库”或“基于Web的数据库”的名号。
12.3分析一个简单的分片场景
分片系统的一个重要特性是,它必须保证数据被平均分散到可用的分片服务器的集合中。这将阻止对集群整体性能产生影响的热点的产生,将它称为需求
1:具有将数据平均分散到所有分片的能力.
:将数据集分散到多个服务器时,将增大由硬件故障导致的数据集的脆弱性。也就是说,随着服务器的增加,所有可用数据受单个服务器故障影响的可能性也更大。可靠分片系统的一个重要特性是,如同磁盘驱动器中常用的RAID系统(磁盘阵列)一样,也将每片数据存储在多个系统中,并且可以容忍单个分片系统不可用的情况。将它称为需求
2:以容错方式存储分片数据的能力
最后,希望可以保证从分片集中添加或删除服务器,而不影响数据的备份和恢复,以便将数据重新分散到更小或更大的分片集中。更进一步,需要能够在不引起集群宕机的情况下完成·服务器的添加和删除。将它称为需求
3:在系统运行时添加或删除分片的能力。
12.4使用MongoDB实现分片
MongoDB使用代理机制实现分片:
其中的mongos守护进程将作为多个基于 mongod的分片服务器的控制器。
当应用连接到mongos进程将把这些分片服务器当作单个MongoDB数据服务器;此后,应用将把它的所有命令(例如更新、查询和删除)都发送到mongos进程。
进程mongos负责管理应用发送到MongoDB服务器的所有命令,该守护进程将跨多个分片的查询重新发送到多个服务器,再将结果聚集在一起。
MongoDB在集合级别实现分片,而不是数据库级别。在许多系统中,只有一个或两个集合可以增长到需要使用分片的地步。因此应该理智地使用分片;如果不需要的话,就不要为较小的集合增加管理分布数据的开销。
现在返回到虚拟的Gaelic社交网络样例。在该应用中,用户集合包含用户和他们资料的细· 节信息。该集合可能会增长到需要分片的地步。不过,其他集合(如事件、国家和州)不可能变得这么大,因此也就不需要使用分片。
分片系统将使用分片键将数据映射到块,块是文档键的逻辑连续范围。每个块标志着分片键值特定连续范围内的许多文档;这些值使mongos控制器可快速找到包含它所需文档的块。
然后MongoDB分片系统将把块存储在可用的分片系统中:配置服务器将记录每个块存储的分片服务器位置。这是分片实现的一个重要特性,因为通过它可以从集合中添加和删除分片,而不需要备份和恢复数据。
在集群中添加新的分片时,该系统将会把许多块迁移到新的服务器集合中,从而平均地分散数据。
类似地,从集群中删除分片时,分片控制器将会从即将离线的分片中抽取所有的块,并重新将它们分散到剩余的分片服务器中。
MongoDB的分片设置还需要存储分片服务器的配置,以及集群中每个分片服务器的信息。为了支持该功能,
需要使用一台称为配置服务器的MongoDB服务器;该服务器实例是一个以特殊角色运行的mongod服务器。
如前所述,配置服务器还可以用作目录,通过它可以找到每个块的位置。在集群中可以具有1台(开发)或3台(生产)配置服务器。
在MongoDB 3.2版中,这有变化。现在可以使用旧的3台配置服务器,也可以使用一个配置复制集。撰写本书时,仍可以使用单个配置服务器(下面就这么做),但它没有提供出现故障时应有的冗余,只能在运行复制集时使用。因此推荐在生产环境中使用3台配置服务器。乍一看,似乎实现分片解决方案需要使用大量服务器!不过,可将多个不同服务的实例添加到同一服务器中,可以在一台相对较小的物理服务器中创建分片(类似于第11章讲解的复制),但需要实行严格的资源管理,以避免MongoDB进程相互之间竞争类似RAM这样的资源。
图12-3显示了一个完全冗余的分片系统,它将为分片存储和配置服务器使用复制集,并且使用一组mongos管理集群。它还显示了如何将这些服务以密集方式运行在3台物理服务器中。
设置分片存储实例的时候一定要仔细,使它们正确地分布在物理服务器之间,只有这样系统才能容忍集群中的一台或多台服务器出现故障。
这种方式与RAID磁盘控制器采取的方式一致,该控制器将把数据分散到条带中的多台服务器,从而使RAID配置可以恢复出现故障的驱动器中的数据。
12.4.1创建分片设置
12.4.2确定连接的方式
12.4.3列出分片服务器的状态
12.4.4使用复制集实现分片
12.5均衡器
12.6哈希片键
12.7标签分片
12.8添加更多配置服务器