网络爬虫之MongoDB数据库的使用

时间:2021-06-30 19:39:37

一.简洁

MongoDB是一款强大、灵活、且易于扩展的通用型数据库

1、易用性

 

MongoDB是一个面向文档(document-oriented)的数据库,而不是关系型数据库。 不采用关系型主要是为了获得更好得扩展性。当然还有一些其他好处,与关系数据库相比,面向文档的数据库不再有“行“(row)的概念取而代之的是更为灵活的“文档”(document)模型。 通过在文档中嵌入文档和数组,面向文档的方法能够仅使用一条记录来表现复杂的层级关系,这与现代的面向对象语言的开发者对数据的看法一致。 另外,不再有预定义模式(predefined schema):文档的键(key)和值(value)不再是固定的类型和大小。由于没有固定的模式,根据需要添加或删除字段变得更容易了。
通常由于开发者能够进行快速迭代,所以开发进程得以加快。而且,实验更容易进行。开发者能尝试大量的数据模型,
从中选一个最好的。

 

2、易扩展性

应用程序数据集的大小正在以不可思议的速度增长。随着可用带宽的增长和存储器价格的下降,即使是一个小规模的应用程序,需要存储的数据量也可能大的惊人,甚至超出
了很多数据库的处理能力。过去非常罕见的T级数据,现在已经是司空见惯了。
由于需要存储的数据量不断增长,开发者面临一个问题:应该如何扩展数据库,分为纵向扩展和横向扩展,纵向扩展是最省力的做法,但缺点是大型机一般都非常贵,而且
当数据量达到机器的物理极限时,花再多的钱也买不到更强的机器了,此时选择横向扩展更为合适,但横向扩展带来的另外一个问题就是需要管理的机器太多。
MongoDB的设计采用横向扩展。面向文档的数据模型使它能很容易地在多台服务器之间进行数据分割。MongoDB能够自动处理跨集群的数据和负载,自动重新分配文档,以及将
用户的请求路由到正确的机器上。这样,开发者能够集中精力编写应用程序,而不需要考虑如何扩展的问题。如果一个集群需要更大的容量,只需要向集群添加新服务器,
MongoDB就会自动将现有的数据向新服务器传送

3、丰富的功能

MongoDB作为一款通用型数据库,除了能够创建、读取、更新和删除数据之外,还提供了一系列不断扩展的独特功能 #1、索引 支持通用二级索引,允许多种快速查询,且提供唯一索引、复合索引、地理空间索引、全文索引 #2、聚合 支持聚合管道,用户能通过简单的片段创建复杂的集合,并通过数据库自动优化 #3、特殊的集合类型 支持存在时间有限的集合,适用于那些将在某个时刻过期的数据,如会话session。类似地,MongoDB也支持固定大小的集合,用于保存近期数据,如日志 #4、文件存储 支持一种非常易用的协议,用于存储大文件和文件元数据。MongoDB并不具备一些在关系型数据库中很普遍的功能,如链接join和复杂的多行事务。省略 这些的功能是处于架构上的考虑,或者说为了得到更好的扩展性,因为在分布式系统中这两个功能难以高效地实现

4、卓越的性能

MongoDB的一个主要目标是提供卓越的性能,这很大程度上决定了MongoDB的设计。MongoDB把尽可能多的内存用作缓存cache,视图为每次查询自动选择正确的索引。
总之各方面的设计都旨在保持它的高性能
虽然MongoDB非常强大并试图保留关系型数据库的很多特性,但它并不追求具备关系型数据库的所有功能。只要有可能,数据库服务器就会将处理逻辑交给客户端。
这种精简方式的设计是MongoDB能够实现如此高性能的原因之一

 

二. MongoDB基础知识

网络爬虫之MongoDB数据库的使用

1、文档是MongoDB的核心概念。文档就是键值对的一个有序集{'msg':'hello','foo':3}。类似于python中的有序字典。

需要注意的是: #1、文档中的键/值对是有序的。 #2、文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。 #3、MongoDB区分类型和大小写。 #4、MongoDB的文档不能有重复的键。 #5、文档中的值可以是多种不同的数据类型,也可以是一个完整的内嵌文档。文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。 文档键命名规范: #1、键不能含有\0 (空字符)。这个字符用来表示键的结尾。 #2、.和$有特别的意义,只有在特定环境下才能使用。 #3、以下划线"_"开头的键是保留的(不是严格要求的)。

2、集合就是一组文档。如果将MongoDB中的一个文档比喻为关系型数据的一行,那么一个集合就是相当于一张表

#1、集合存在于数据库中,通常情况下为了方便管理,不同格式和类型的数据应该插入到不同的集合,但其实集合没有固定的结构,这意味着我们完全可以把不同格式和类型的数据统统插入一个集合中。 #2、组织子集合的方式就是使用“.”,分隔不同命名空间的子集合。 比如一个具有博客功能的应用可能包含两个集合,分别是blog.posts和blog.authors,这是为了使组织结构更清晰,这里的blog集合(这个集合甚至不需要存在)跟它的两个子集合没有任何关系。 在MongoDB中,使用子集合来组织数据非常高效,值得推荐 #3、当第一个文档插入时,集合就会被创建。合法的集合名: 集合名不能是空字符串""。 集合名不能含有\0字符(空字符),这个字符表示集合名的结尾。 集合名不能以"system."开头,这是为系统集合保留的前缀。 用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的集合中包含该字符。除非你要访问这种系统创建的集合,否则千万不要在名字里出现$。

 3、数据库:在MongoDB中,多个文档组成集合,多个集合可以组成数据库

数据库也通过名字来标识。数据库名可以是满足以下条件的任意UTF-8字符串: #1、不能是空字符串("")。 #2、不得含有' '(空格)、.、$、/、\和\0 (空字符)。 #3、应全部小写。 #4、最多64字节。 有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库。 #1、admin: 从身份认证的角度讲,这是“root”数据库,如果将一个用户添加到admin数据库,这个用户将自动
获得所有数据库的权限。再者,一些特定的服务器端命令也只能从admin数据库运行,如列出所有数据库或关闭服务器 #
2、local: 这个数据库永远都不可以复制,且一台服务器上的所有本地集合都可以存储在这个数据库中 #3、config: MongoDB用于分片设置时,分片信息会存储在config数据库中

4、强调:把数据库名添加到集合名前,得到集合的完全限定名,即命名空间

例如:
如果要使用cms数据库中的blog.posts集合,这个集合的命名空间就是
cmd.blog.posts。命名空间的长度不得超过121个字节,且在实际使用中应该小于100个字节

网络爬虫之MongoDB数据库的使用

三.MongoDB的安装与使用

01】windows下安装首先去官网下载: https://www.mongodb.com/dr/fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-3.4.4-signed.msi/download
02】下载后安装,安装完毕后,将bin目录配置到系统的环境变量中去 【03】进入到安装目录下新建文件夹: 首先新建一个data目录: D:\ProfessionalSoftwares\mongodb\data 然后在data目录下新建两个文件夹:db和logs 最后在logs目录下新建一个文件:mongo.log 【04】现在我们将mongoDB做成一个服务然后在后台运行,这样我们每次开机就可以使用MongoDB服务端了: 首先以管理员身份运行cmd命令行,然后在命令行中执行如下的命令:(因为我配置了环境变量,所以可以直接使用 mongod命令) mongod --bind_ip 0.0.0.0 --logpath D:\ProfessionalSoftwares\mongodb\data\logs\mongo.log
--logappend --dbpath D:\ProfessionalSoftwares\mongodb\data\db --port 27017
--serviceName "MongoDB" --serviceDisplayName "MongoDB" --install --auth 上述--install参数表示将mongodb作为一个服务进行安装,--auth表示我客户端链接mongodb服务端时,需要输入指定的用户名和密码 安装完毕后,然后在刚才开启的管理员cmd命令行中启动MongoDB服务: net start MongoDB 这里的MongoDB就是上面命令中的服务名:serviceName 另外如果需要关闭MongoDB这个服务,只需要使用net stop MongoDB即可 【05】最终操作完毕后,我们在浏览器中输入如下的网址:http://localhost:27017/ 显示这句话就表示我们安装成功:
It looks like you are trying to access MongoDB over HTTP on the native driver port.

2.账号管理

数据库一般都是有相应的账号和密码的,MongoDB也有:

#账号管理,参考官网地址:https://docs.mongodb.com/master/tutorial/enable-authentication/
 #1、创建账号,这里我们相当于创建了一个管理员账号root,然后在使用Robomongo登入数据库时,需要输入验证, 要不然会报错:Failed to execute "listdatabases" command. 笔者在这里坑了好久 默认情况下,MongoDB存在两个数据库:admin和test,我们创建管理员账户时,一般都在admin数据库下 注意下面的步骤,都是需要在管理员权限的cmd命令行下执行: 接着上面的说,在初始环境下登入到MongoDB数据库后,我们直接使用admin数据库,然后创建账号 use admin db.createUser( { user: "root", pwd: "cisco123", roles: [ { role: "root", db: "admin" } ] } ) #2、重启数据库 创建完管理员账号和密码后,我们首先退出MongoDb数据库,然后将刚才安装的MongoDB数据库服务移除: 先关闭服务:net stop MongoDB 然后删除: mongod --remove 移除后,我们再来重新安装服务,这次安装我们加入了--auth参数, 该参数表示,下次客户端连接MongoDB数据库时候,需要输入用户名和密码,如下所示: mongod --bind_ip 0.0.0.0 --logpath D:\ProfessionalSoftwares\mongodb\data\logs\mongo.log --logappend --dbpath D:\ProfessionalSoftwares\mongodb\data\db --port 27017 --serviceName "MongoDB" --serviceDisplayName "MongoDB"  --install  --auth 然后再来重启服务: net start MongoDB 现在我们来使用账号和密码登入MongoDB数据库,注意后面我们需要指定相应的数据库名称:admin 因为我们的管理员账号和密码是在admin数据库下新建的: #3、登录:注意使用双引号而非单引号 mongo --port 27017 -u "root" -p "cisco123" --authenticationDatabase "admin" 也可以在登录之后用db.auth("账号","密码")登录 mongo use admin db.auth("root","cisco123") 关于MongoDB的详细信息可以关注这篇博客: #推荐博客:https://www.cnblogs.com/zhoujinyi/p/4610050.html

四 MongoDB的基本数据类型

1、在概念上,MongoDB的文档与Javascript的对象相近,因而可以认为它类似于JSON。
JSON(http://www.json.org)是一种简单的数据表示方式:其规范仅用一段文字就能描述清楚(其官网证明了这点),且仅包含六种数据类型。 2、这样有很多好处:易于理解、易于解析、易于记忆。然而从另一方面说,因为只有null、布尔、数字、字符串、
数字和对象这几种数据类型,所以JSON的表达能力有一定的局限。
3、虽然JSON具备的这些类型已经具有很强的表现力,但绝大数应用(尤其是在于数据库打交道时)都还需要其他一些重要的类型。
例如,JSON没有日期类型,这使得原本容易日期处理变得烦人。另外,JSON只有一种数字类型,无法区分浮点数和整数,更别区分32位和64位了。再者JSON无法表示其他一些通用类型,如正则表达式或函数。
4、MongoDB在保留了JSON基本键/值对特性的基础上,添加了其他一些数据类型。在不同的编程语言下,这些类型的确切表示有些许差异。下面说明了MongoDB支持的其他通用类型,以及如何使用它们

 MongoDB支持的通用数据类型:

#1null:用于表示空或不存在的字段 d={'x':null} #2、布尔型:true和false,注意这里的true和false都是小写 d={'x':true,'y':false} #3、数值 整型和浮点型 d={'x':3,'y':3.1415926} #4、字符串 d={'x':'egon'} #5、日期 可以接收一个日期对象 d={'x':new Date()} d.x.getHours() #6、正则表达式 d={'pattern':/^egon.*?nb$/i} 正则写在//内,后面的i代表: i 忽略大小写 m 多行匹配模式 x 忽略非转义的空白字符 s 单行匹配模式 #7、数组:数组中的元素可以是整数,也可以是字符串 d={'x':[1,'a','v']} #8、内嵌文档,表示value也可以是一个文档, 如下面所示,我想访问country对应的value:user.addr.country即可: user={'name':'egon','addr':{'country':'China','city':'YT'}} user.addr.country #9、对象id:是一个12字节的ID,是文档的唯一标识,不可变 d={'x':ObjectId()}

例如我使用MongoDB中的数据类型来定义一个用户记录:

 

{"_id":ObjectId(),"name":'carson','is_admin':true, 'age':18,'salary':18000, 'hobbies':[1,'a'], 'comments':null}

 

5、_id和ObjectId

网络爬虫之MongoDB数据库的使用

五 CRUD操作

1、数据库操作(增删改查)

#1、新增数据库,需要说明的是,这里不需要像Mysql数据库那样判断下数据库是否存在 #如果数据库config不存在,则创建数据库config;如果存在,那就切换到该数据库 这里使用use来新增数据库 use config #2、查 show dbs #查看所有的数据库 可以看到,我们刚创建的数据库config并不在数据库的列表中, MongoDB数据库和其他的不一样,如果一个新的数据库中没有任何集合,那么就不会展示它, 为了显示该数据库,我们需要向config数据库插入一些数据。 db.table1.insert({'a':1}) 然后再来查询: 细心的你可能发现了,我们并没有给config数据库建立表结构,那为什么这里可以使用table1 原因在于mongodb压根不需要建立表,因为它根本没有表结构,我们往表中插入数据时,这个表就自动建立起来了 > db.table1.insert({'a':1}) WriteResult({ "nInserted" : 1 }) > show dbs admin 0.000GB config 0.000GB database1 0.000GB local 0.000GB test 0.000GB 3.查看当前使用的数据库:db 一旦你登入mongodb,那么就会给db赋予一个默认值,默认是test数据库,即你默认是在test数据库下面 这样的好处在于,不管我们怎么切换数据,如果需要对该数据库进行操作,那我们只需要使用db来代表当前的数据库即可:因此use config 相当于 db=test > db database1 > use test switched to db test > db test > #4、删除数据库, use config #先切换到要删的库下 db.dropDatabase() #删除当前库 如下所示: > db config > db.dropDatabase() { "dropped" : "config", "ok" : 1 } >

5.另外如果我们需要查看数据库有哪些操作方法,直接使用db.help()即可:

2、集合操作(类似于Mysql中的表操作)

当我们讨论集合操作,其实就相当于讨论的是关系型数据库中的表操作,因为两者是对应的:

#1、增 当第一个文档插入时,集合就会被创建 > use database1 switched to db database1 > db.table1.insert({'a':1}) WriteResult({ "nInserted" : 1 }) > db.table2.insert({'b':1}) WriteResult({ "nInserted" : 1 }) > # 查询数据库database1下面的表有哪几张,其实质就是查询数据库下的集合有哪些 > show tables; table1 table2 # 删除表中的集合,使用drop() > db.table1.drop() true

> show tables; table2 >

我们在为MongoDB中的表命名时候,需要按照一定的规则联系起来,如下图所示:
例如我们之间所做的博客系统,有用户表和评论表,我们使用外键将它们俩关联起来,但是在
MongoDB中,我们直接使用.的方式即可关联起来:
db.blog.user.inser()
db.blog.comments.insert()

在前面我们说过,MongoDB中默认会为我们的每条记录新增一个"_id"字段,该字段用来唯一标识某个集合中的一条文档,我们也可以自定义id属性,不过要注意,自定义时,这个字段要叫做 _id,如下所示:

> db.emp.insert({'_id':1, 'name': 'carson'}) # 自定义属性 WriteResult({ "nInserted" : 1 }) > db.emp.findOne() { "_id" : 1, "name" : "carson" } > db.emp.insert({'name':'alex'}) WriteResult({ "nInserted" : 1 }) > db.emp.find() { "_id" : 1, "name" : "carson" } { "_id" : ObjectId("5a5c5d5d8c6f3bc41b4589b2"), "name" : "alex" } > db.emp.insert({'name':'eva','salary':18000}) WriteResult({ "nInserted" : 1 }) > db.emp.find() { "_id" : 1, "name" : "carson" } { "_id" : ObjectId("5a5c5d5d8c6f3bc41b4589b2"), "name" : "alex" } { "_id" : ObjectId("5a5c5dfb8c6f3bc41b4589b3"), "name" : "eva", "salary" : 18000 } > db.emp.insert({'_id':1001, 'name': 'alex666'}) WriteResult({ "nInserted" : 1 }) > db.emp.find() { "_id" : 1, "name" : "carson" } { "_id" : ObjectId("5a5c5d5d8c6f3bc41b4589b2"), "name" : "alex" } { "_id" : ObjectId("5a5c5dfb8c6f3bc41b4589b3"), "name" : "eva", "salary" : 18000 } { "_id" : 1001, "name" : "alex666" }

3、文档操作

新增文档(新增记录)

#创建一个user的局部变量,这是一个JavaScript对象 user={ "name":"carson", 'is_nb':true, 'hobbies':['music','read','dancing'] } db.userinfo.insert(user) db.userinfo.find() user1={ "name":"tom", 'is_sb':true, 'hobbies':['music','read','dancing'] } user2={ "name":"eva", 'is_sb':'wxx', 'hobbies':['music','read','dancing'] } user3={ "name":"carson666", 'is_sb':false, 'hobbies':['music','read','dancing'] } # 一次性插入多条记录(文档) db.userinfo.insertMany([user1,user2,user3])

当我们查询记录时,如果想让查询结果更好的展示,使用pretty()方法即可:

网络爬虫之MongoDB数据库的使用

 

 修改文档:

update() 方法用于更新已存在的文档。语法格式如下: db.collection.update( <query>, <update>, { upsert: <boolean>, multi: <boolean>, writeConcern: <document> } ) 参数说明:对比update db1.t1 set name='EGON',sex='Male' where name='egon' and age=18; query : 相当于where条件。 update : update的对象和一些更新的操作符(如$,$inc...等,相当于set后面的 upsert : 可选,默认为false,代表如果不存在update的记录不更新也不插入,设置为true代表插入。 multi : 可选,默认为false,代表只更新找到的第一条记录,设为true,代表更新找到的全部记录。 writeConcern :可选,抛出异常的级别。 更新操作是不可分割的:若两个更新同时发送,先到达服务器的先执行,然后执行另外一个,不会破坏文档。

对文档的更新,我们使用.来进行操作:首先找到要更新的对象,然后使用.取出文档对应的属性,来看下面的例子:

# 先找到要修改的文档对象 carson 使用var关键字声明 > var carson=db.userinfo.findOne({'name':'carson'}) > carson { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "name" : "carson", "is_nb" : true, "hobbies" : [ "music", "read", "dancing" ] } # 为carson文档对象新增一个属性relationship,其对应的值为:{'girl_friends':33,'wives':23} 可以看到value对应的值类型又可以是一个文档 > carson.relationship={'girl_friends':33,'wives':23} { "girl_friends" : 33, "wives" : 23 } > carson { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "name" : "carson", "is_nb" : true, "hobbies" : [ "music", "read", "dancing" ], "relationship" : { "girl_friends" : 33, "wives" : 23 } } # 为carson文档对象新增一个属性username,其值为carson.name > carson.username=carson.name carson > carson { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "name" : "carson", "is_nb" : true, "hobbies" : [ "music", "read", "dancing" ], "relationship" : { "girl_friends" : 33, "wives" : 23 }, "username" : "carson" } > carson.girl_friends=33
33
> carson { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "name" : "carson", "is_nb" : true, "hobbies" : [ "music", "read", "dancing" ], "relationship" : { "girl_friends" : 33, "wives" : 23 }, "username" : "carson", "girl_friends" : 33 } > carson.wives = 23
23
> carson { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "name" : "carson", "is_nb" : true, "hobbies" : [ "music", "read", "dancing" ], "relationship" : { "girl_friends" : 33, "wives" : 23 }, "username" : "carson", "girl_friends" : 33, "wives" : 23 } # 删掉没有用的 > delete carson.relationship true
> carson { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "name" : "carson", "is_nb" : true, "hobbies" : [ "music", "read", "dancing" ], "username" : "carson", "girl_friends" : 33, "wives" : 23 }

我们来看下面一个常见的更新错误:

 

现在我们往集合userinfo中新增三个文档对象,每个文档对象中的用户名刚好相同 db.userinfo.insert({'name':'angina','age':10}) db.userinfo.insert({'name':'angina','age':20}) db.userinfo.insert({'name':'angina','age':30}) > db.userinfo.find() { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "name" : "carson", "is_nb" : true, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b5"), "name" : "tom", "is_sb" : true, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b6"), "name" : "eva", "is_sb" : "wxx", "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b7"), "name" : "carson666", "is_sb" : false, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b8"), "name" : "angina", "age" : 10 } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b9"), "name" : "angina", "age" : 20 } { "_id" : ObjectId("5a5c6a6e8c6f3bc41b4589ba"), "name" : "angina", "age" : 30 } # 找到的是第二个angina,他要过生日,于是长了一岁 > var angina = db.userinfo.findOne({'name':'angina', 'age':20}) > angina.age++
20 # 发现angina这条文档对象对应的age属性自增了1岁 > angina { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b9"), "name" : "angina", "age" : 21 } # 但是我们发现原始集合中的userinfo并没有任何改变,还是20岁,所以我们取出来修改后,最后 # 还要更新到集合中才算正式修改 > db.userinfo.find() { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "name" : "carson", "is_nb" : true, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b5"), "name" : "tom", "is_sb" : true, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b6"), "name" : "eva", "is_sb" : "wxx", "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b7"), "name" : "carson666", "is_sb" : false, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b8"), "name" : "angina", "age" : 10 } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b9"), "name" : "angina", "age" : 20 } { "_id" : ObjectId("5a5c6a6e8c6f3bc41b4589ba"), "name" : "angina", "age" : 30 } # 将修改的变化同步更新到userinfo集合中,我们的条件只定位到第二条记录这一条记录,所以更新是没问题的, > db.userinfo.update({'name':'angina', 'age':20},angina) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) # 然后再来查看,发现修改成功 > db.userinfo.find() { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "name" : "carson", "is_nb" : true, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b5"), "name" : "tom", "is_sb" : true, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b6"), "name" : "eva", "is_sb" : "wxx", "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b7"), "name" : "carson666", "is_sb" : false, "hobbies" : [ "music", "read", "dancing" ] }suo'y
{ "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b8"), "name" : "angina", "age" : 10 } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b9"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c6a6e8c6f3bc41b4589ba"), "name" : "angina", "age" : 30 } # 这里我们仅仅是按照name来匹配集合中的文档,这里匹配到了三条,但MongoDB是没办法将 # 三条文档对象都修改成同一个_id,zheli > db.userinfo.update({'name':'angina'}, obj) 2018-01-15T16:57:08.822+0800 E QUERY    [thread1] ReferenceError: obj is not defined : @(shell):1:21 # 删除掉angina文档对象的ID > delete angina._id true
> angina { "name" : "angina", "age" : 21 } # 此时集合中的文档对象信息如下所示: > db.userinfo.find() { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "name" : "carson", "is_nb" : true, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b5"), "name" : "tom", "is_sb" : true, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b6"), "name" : "eva", "is_sb" : "wxx", "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b7"), "name" : "carson666", "is_sb" : false, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b8"), "name" : "angina", "age" : 10 } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b9"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c6a6e8c6f3bc41b4589ba"), "name" : "angina", "age" : 30 } # 此时再来更新,发现居然更新成功 > db.userinfo.update({"name":"angina"},angina) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) # 我们查询,发现此时更新的是第一条 > db.userinfo.find() { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "name" : "carson", "is_nb" : true, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b5"), "name" : "tom", "is_sb" : true, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b6"), "name" : "eva", "is_sb" : "wxx", "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b7"), "name" : "carson666", "is_sb" : false, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b8"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b9"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c6a6e8c6f3bc41b4589ba"), "name" : "angina", "age" : 30 } # 针对这种情况,我们还是以id来选中第二条记录 > db.userinfo.update({"_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b9")}, angina) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) # 由于此时angina文档对象的age依然为21,所以在集合中同步更新后,依然也是21 > db.userinfo.find() { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "name" : "carson", "is_nb" : true, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b5"), "name" : "tom", "is_sb" : true, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b6"), "name" : "eva", "is_sb" : "wxx", "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b7"), "name" : "carson666", "is_sb" : false, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b8"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b9"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c6a6e8c6f3bc41b4589ba"), "name" : "angina", "age" : 30 } > # 现在我想更新多条,即将name属性值为angina的文档对象的age属性都更新为21,怎么办?使用multi:true关键字即可 >
> db.userinfo.update({"name":'angina'}, angina, {'multi':true}) WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0, "writeError" : { "code" : 9, "errmsg" : "multi update only works with $ operators" # 提示报错,只能用修改器 } })

 

接着上面的,我们使用$set:angina来结合multi:true即可完成修改,不过这里的前提是将angina文档对象的id删除了

> db.userinfo.update({"name":'angina'}, {$set:angina}, {'multi':true}) WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 1 }) > db.userinfo.find() { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "name" : "carson", "is_nb" : true, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b5"), "name" : "tom", "is_sb" : true, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b6"), "name" : "eva", "is_sb" : "wxx", "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b7"), "name" : "carson666", "is_sb" : false, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b8"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b9"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c6a6e8c6f3bc41b4589ba"), "name" : "angina", "age" : 21 }

 

 

六.使用修改器

 

db.users.insert({'name':'angina','age':10}) db.users.insert({'name':'angina','age':20}) db.users.insert({'name':'angina','age':30}) 1"$set"修改器 > db.users.find() { "_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "name" : "angina", "age" : 10 } { "_id" : ObjectId("5a5c83c48c6f3bc41b4589bf"), "name" : "angina", "age" : 20 } { "_id" : ObjectId("5a5c83c58c6f3bc41b4589c0"), "name" : "angina", "age" : 30 } > db.users.update({'_id': ObjectId("5a5c83c48c6f3bc41b4589be")},{'age':111}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) """ 完全覆盖了原文档: 原来的文档对象是:"_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "name" : "angina", "age" : 10 现在变为:"_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "age" : 111
""" > db.users.find() { "_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "age" : 111 } { "_id" : ObjectId("5a5c83c48c6f3bc41b4589bf"), "name" : "angina", "age" : 20 } { "_id" : ObjectId("5a5c83c58c6f3bc41b4589c0"), "name" : "angina", "age" : 30 } """ 使用#$set只更新原文档的一部分 原来是"_id" : ObjectId("5a5c83c48c6f3bc41b4589bf"), "name" : "angina", "age" : 20 现在变为:"_id" : ObjectId("5a5c83c48c6f3bc41b4589bf"), "name" : "angina", "age" : 222 $set对应的value为要修改的目标的值 """ > db.users.update({'_id':ObjectId("5a5c83c48c6f3bc41b4589bf")},{'$set':{'age':222}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.users.find() { "_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "age" : 111 } { "_id" : ObjectId("5a5c83c48c6f3bc41b4589bf"), "name" : "angina", "age" : 222 } { "_id" : ObjectId("5a5c83c58c6f3bc41b4589c0"), "name" : "angina", "age" : 30 } # 现在往原始集合中再添加一条文档 > db.users.insert({'name':'angina','age':40,'addr':{'country':'China','city':'BJ'}}) WriteResult({ "nInserted" : 1 }) > db.users.find() { "_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "age" : 111 } { "_id" : ObjectId("5a5c83c48c6f3bc41b4589bf"), "name" : "angina", "age" : 222 } { "_id" : ObjectId("5a5c83c58c6f3bc41b4589c0"), "name" : "angina", "age" : 30 } { "_id" : ObjectId("5a5c854e8c6f3bc41b4589c1"), "name" : "angina", "age" : 40, "addr" : { "country" : "China", "city" : "BJ" } } # 接着再添加一条: > db.users.insert({'name':'angina','age':50,'addr':{'country':'USA','city':'ShangHai'}}) WriteResult({ "nInserted" : 1 }) > db.users.find() { "_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "age" : 111 } { "_id" : ObjectId("5a5c83c48c6f3bc41b4589bf"), "name" : "angina", "age" : 222 } { "_id" : ObjectId("5a5c83c58c6f3bc41b4589c0"), "name" : "angina", "age" : 30 } { "_id" : ObjectId("5a5c854e8c6f3bc41b4589c1"), "name" : "angina", "age" : 40, "addr" : { "country" : "China", "city" : "BJ" } } { "_id" : ObjectId("5a5c856d8c6f3bc41b4589c2"), "name" : "angina", "age" : 50, "addr" : { "country" : "USA", "city" : "ShangHai" } } > db.users.find() { "_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "age" : 111 } { "_id" : ObjectId("5a5c83c48c6f3bc41b4589bf"), "name" : "angina", "age" : 222 } { "_id" : ObjectId("5a5c83c58c6f3bc41b4589c0"), "name" : "angina", "age" : 30 } { "_id" : ObjectId("5a5c854e8c6f3bc41b4589c1"), "name" : "angina", "age" : 40, "addr" : { "country" : "China", "city" : "BJ" } } { "_id" : ObjectId("5a5c856d8c6f3bc41b4589c2"), "name" : "angina", "age" : 50, "addr" : { "country" : "USA", "city" : "ShangHai" } } """ 这里我本来想做的是对name为angina的文档对象,将他们的addr值修改为:{'country':'China','city':'BJ'} 但实际上只是修改了匹配的第一条,那如果我想修改所有的怎么办? """ > db.users.update({"name":"angina"},{'$set':{'addr':{'country':'China','city':'BJ'}}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.users.find() { "_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "age" : 111 } { "_id" : ObjectId("5a5c83c48c6f3bc41b4589bf"), "name" : "angina", "age" : 222, "addr" : { "country" : "China", "city" : "BJ" } } { "_id" : ObjectId("5a5c83c58c6f3bc41b4589c0"), "name" : "angina", "age" : 30 } { "_id" : ObjectId("5a5c854e8c6f3bc41b4589c1"), "name" : "angina", "age" : 40, "addr" : { "country" : "China", "city" : "BJ" } } { "_id" : ObjectId("5a5c856d8c6f3bc41b4589c2"), "name" : "angina", "age" : 50, "addr" : { "country" : "USA", "city" : "ShangHai" } } """ 下面的操作就是将age为30岁的文档对象添加一个addr属性,因为该文档对象并没有addr属性,所以这里默认就是新增了 """ > db.users.update({'age':30},{'$set':{'addr':{'country':'China','city':'BJ'}}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.users.find() { "_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "age" : 111 } { "_id" : ObjectId("5a5c83c48c6f3bc41b4589bf"), "name" : "angina", "age" : 222, "addr" : { "country" : "China", "city" : "BJ" } } { "_id" : ObjectId("5a5c83c58c6f3bc41b4589c0"), "name" : "angina", "age" : 30, "addr" : { "country" : "China", "city" : "BJ" } } { "_id" : ObjectId("5a5c854e8c6f3bc41b4589c1"), "name" : "angina", "age" : 40, "addr" : { "country" : "China", "city" : "BJ" } } { "_id" : ObjectId("5a5c856d8c6f3bc41b4589c2"), "name" : "angina", "age" : 50, "addr" : { "country" : "USA", "city" : "ShangHai" } } """ 将age为50的文档对象为的地址修改为:{'country':'China','city':'BJ'} 原来是{ "country" : "USA", "city" : "ShangHai" } 因此可以总结:update结合$set的使用原则: 如果对应的文档对象中有这个属性,那么就再修改,没有就添加 """ db.users.update({'age':50},{'$set':{'addr':{'country':'China','city':'BJ'}}}) # 下面就是修改内嵌文档,所谓内嵌文档,即value的类型是一个字典(又是一个文档对象) 这里是将age为30的文档对象的addr属性对应的country属性值修改为CHINA 原来是China ,现在变成了CHINA >
> db.users.update({'age':30},{'$set':{'addr.country':'CHINA'}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.users.find() { "_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "age" : 111 } { "_id" : ObjectId("5a5c83c48c6f3bc41b4589bf"), "name" : "angina", "age" : 222, "addr" : { "country" : "China", "city" : "BJ" } } { "_id" : ObjectId("5a5c83c58c6f3bc41b4589c0"), "name" : "angina", "age" : 30, "addr" : { "country" : "CHINA", "city" : "BJ" } } { "_id" : ObjectId("5a5c854e8c6f3bc41b4589c1"), "name" : "angina", "age" : 40, "addr" : { "country" : "China", "city" : "BJ" } } { "_id" : ObjectId("5a5c856d8c6f3bc41b4589c2"), "name" : "angina", "age" : 50, "addr" : { "country" : "USA", "city" : "ShangHai" } } >

""" 这里的unset相当于就是将addr对应的键和值给清空掉 原来是 { "_id" : ObjectId("5a5c854e8c6f3bc41b4589c1"), "name" : "angina", "age" : 40, "addr" : { "country" : "China", "city" : "BJ" } } 现在是 { "_id" : ObjectId("5a5c854e8c6f3bc41b4589c1"), "name" : "angina", "age" : 40 } """"
> db.users.update({'age':40},{'$unset':{'addr':'umpty'}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.users.find() { "_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "age" : 111 } { "_id" : ObjectId("5a5c83c48c6f3bc41b4589bf"), "name" : "angina", "age" : 222, "addr" : { "country" : "China", "city" : "BJ" } } { "_id" : ObjectId("5a5c83c58c6f3bc41b4589c0"), "name" : "angina", "age" : 30 } { "_id" : ObjectId("5a5c854e8c6f3bc41b4589c1"), "name" : "angina", "age" : 40 } { "_id" : ObjectId("5a5c856d8c6f3bc41b4589c2"), "name" : "angina", "age" : 50, "addr" : { "country" : "China", "city" : "BJ" } }

我们再通过一个需求来看看unset的作用:

db.user.insert( { "_id": ObjectId("521d9c18b34cd9052000000a"), "allylist": { "1987": { } }, "allyreq": { "1": true, "2": true, "3": true }, "energy": 100, "exp": 200, "formation": { "id": 0, "positionlist": [ NumberLong(0), NumberLong(0), NumberLong(0), NumberLong(0), NumberLong(0), NumberLong(0), NumberLong(0), NumberLong(0), NumberLong(0) ] }, "gold": 10000, "heroghost": 20000, "iconid": 1, "level": 10, "name": "cs9", "name2": "Roger", "name3": { "name": "Roger" }, "password": "123", "sex": 1, "userid": NumberLong(9) })

需求 :我现在想allyreq里面的1这个key和value都删除掉,如下:

db.user.update({"userid":9},{"$unset":{"allyreq.1":true}})

再来查看,发现没有了:

> db.user.find().pretty() { "_id" : ObjectId("521d9c18b34cd9052000000a"), "allylist" : { "1987" : { } }, "allyreq" : { "2" : true, "3" : true }, "energy" : 100, "exp" : 200, "formation" : { "id" : 0, "positionlist" : [ NumberLong(0), NumberLong(0), NumberLong(0), NumberLong(0), NumberLong(0), NumberLong(0), NumberLong(0), NumberLong(0), NumberLong(0) ] }, "gold" : 10000, "heroghost" : 20000, "iconid" : 1, "level" : 10, "name" : "cs9", "name2" : "Roger", "name3" : { "name" : "Roger" }, "password" : "123", "sex" : 1, "userid" : NumberLong(9) }

现在我想让它还原,使用set即可:

> db.user.update({"userid":9},{"$set":{"allyreq.1":true}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.user.find().pretty() { "_id" : ObjectId("521d9c18b34cd9052000000a"), "allylist" : { "1987" : { } }, "allyreq" : { "2" : true, "3" : true, "1" : true # 注意这里是有序添加,自动添加到字典的后面 }, "energy" : 100, "exp" : 200, "formation" : { "id" : 0, "positionlist" : [ NumberLong(0), NumberLong(0), NumberLong(0), NumberLong(0), NumberLong(0), NumberLong(0), NumberLong(0), NumberLong(0), NumberLong(0) ] }, "gold" : 10000, "heroghost" : 20000, "iconid" : 1, "level" : 10, "name" : "cs9", "name2" : "Roger", "name3" : { "name" : "Roger" }, "password" : "123", "sex" : 1, "userid" : NumberLong(9) }

3、往数组内添加元素

 

如果数组已经存在,"$push"会向已有的数组末尾加入一个元素,要是没有就创建一个新的数组。 例如提交博客的评论 db.blog.insert({'_id':1,'name':'carson意外死亡的真相'}) db.blog.update({'_id':1},{'$push':{'comments':{"name":"egon","content":'alex是谁???'}}}) db.blog.update({'_id':1},{'$push':{'comments':{"name":"wxx","content":'我去,真的假的'}}}) db.blog.update({'_id':1},{'$push':{'comments':{"name":"yxx","content":'吃喝嫖赌抽,欠下两个亿'}}}) # 使用$each一次性添加多个评论文档对象,多个评论文档对象组成一个数组 db.blog.update({'_id':1},{'$push':{'comments':{'$each':[ {'name':'xxx','content':'二鞠躬'}, {'name':'yyy','content':'三鞠躬'}, {'name':'yyy','content':'四鞠躬'}, {'name':'zzz','content':'五鞠躬'}, {'name':'mmm','content':'六鞠躬'}, {'name':'nnn','content':'七鞠躬'}, ]}}}) # 一次性添加完毕一个文档对象数组,然后截取最后7条文档对象 # 注意这里截取完毕后,我们再来打印db.blog.find()获取的就是最后7条文档对象了 db.blog.update({'_id':1},{'$push':{'comments':{'$each':[ {'name':'xxx','content':'二鞠躬'}, {'name':'yyy','content':'三鞠躬'}, {'name':'yyy','content':'四鞠躬'}, {'name':'zzz','content':'五鞠躬'}, {'name':'mmm','content':'六鞠躬'}, {'name':'nnn','content':'七鞠躬'}, ], '$slice':-7 }}}) > db.blog.insert({'_id':1,'name':'carson意外死亡的真相'}) WriteResult({ "nInserted" : 1 }) > db.blog.find() { "_id" : 1, "name" : "carson意外死亡的真相" } > db.blog.update({'_id':1},{'$push':{'comments':{"name":"egon","content":'alex是谁???'}}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.blog.update({'_id':1},{'$push':{'comments':{"name":"wxx","content":'我去,真的假的'}}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.blog.update({'_id':1},{'$push':{'comments':{"name":"yxx","content":'吃喝嫖赌抽,欠下两个亿'}}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.blog.find().pretty() { "_id" : 1, "name" : "carson意外死亡的真相", "comments" : [ { "name" : "egon", "content" : "alex是谁???" }, { "name" : "wxx", "content" : "我去,真的假的" }, { "name" : "yxx", "content" : "吃喝嫖赌抽,欠下两个亿" } ] } > db.blog.update({'_id':1},{'$push':{'comments':{'$each':[{'name':'oldboy','content':'鼓掌'},{'name':'oldgirl','content':'一鞠躬'}]}}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.blog.find().pretty() { "_id" : 1, "name" : "carson意外死亡的真相", "comments" : [ { "name" : "egon", "content" : "alex是谁???" }, { "name" : "wxx", "content" : "我去,真的假的" }, { "name" : "yxx", "content" : "吃喝嫖赌抽,欠下两个亿" }, { "name" : "oldboy", "content" : "鼓掌" }, { "name" : "oldgirl", "content" : "一鞠躬" } ] } # 使用$each一次性添加多个评论文档对象,多个评论文档对象组成一个数组 > db.blog.update({'_id':1},{'$push':{'comments':{'$each':[ ... {'name':'xxx','content':'二鞠躬'}, ... {'name':'yyy','content':'三鞠躬'}, ... {'name':'yyy','content':'四鞠躬'}, ... {'name':'zzz','content':'五鞠躬'}, ... {'name':'mmm','content':'六鞠躬'}, ... {'name':'nnn','content':'七鞠躬'}, ... ]}}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.blog.find().pretty() { 七鞠躬'}, ]}}})
        "_id" : 1, "name" : "carson意外死亡的真相", "comments" : [ { "name" : "egon", "content" : "alex是谁???" }, { "name" : "wxx", "content" : "我去,真的假的" }, { "name" : "yxx", "content" : "吃喝嫖赌抽,欠下两个亿" }, { "name" : "oldboy", "content" : "鼓掌" }, { "name" : "oldgirl", "content" : "一鞠躬" }, { "name" : "xxx", "content" : "二鞠躬" }, { "name" : "yyy", "content" : "三鞠躬" }, { "name" : "yyy", "content" : "四鞠躬" }, { "name" : "zzz", "content" : "五鞠躬" }, { "name" : "mmm", "content" : "六鞠躬" }, { "name" : "nnn", "content" : "七鞠躬" } ] } # 再继续使用$each一次性添加六条评论,同时截取最后的7条评论,使用$slice来限制获取的评论的条数
# 即通过该参数来限制大小,只保留最后n个文档对象
> db.blog.update({'_id':1},{'$push':{'comments':{'$each':[ ... {'name':'xxx','content':'八鞠躬'}, ... {'name':'yyy','content':'九鞠躬'}, ... {'name':'yyy','content':'十鞠躬'}, ... {'name':'zzz','content':'十一鞠躬'}, ... {'name':'mmm','content':'十二鞠躬'}, ... {'name':'nnn','content':'十三鞠躬'}, ... ], ... '$slice':-7 ... }}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) # 注意这里截取完毕后,我们再来打印db.blog.find()获取的就是最后7条文档对象了 > db.blog.find().pretty() { "_id" : 1, "name" : "carson意外死亡的真相", "comments" : [ { "name" : "nnn", "content" : "七鞠躬" }, { "name" : "xxx", "content" : "八鞠躬" }, { "name" : "yyy", "content" : "九鞠躬" }, { "name" : "yyy", "content" : "十鞠躬" }, { "name" : "zzz", "content" : "十一鞠躬" }, { "name" : "mmm", "content" : "十二鞠躬" }, { "name" : "nnn", "content" : "十三鞠躬" } ] }

 

 

5、避免添加重复 "$addToSet"

#=======> 添加新的数组 > db.urls.insert({'_id':1,'urls':[]}) WriteResult({ "nInserted" : 1 }) > db.urls.insert({'_id':2,'urls':[]}) WriteResult({ "nInserted" : 1 }) > db.urls.find() { "_id" : 1, "urls" : [ ] } { "_id" : 2, "urls" : [ ] } # 使用$addToSet避免重复向urls对应的数组中重复添加元素,可以看到最终 # 我们打印的时候,结果是http://www.baidu.com这个域名被添加进去了1次
 db.urls.update({'_id':1},{'$addToSet':{'urls':'http://www.baidu.com'}}) db.urls.update({'_id':1},{'$addToSet':{'urls':'http://www.baidu.com'}}) db.urls.update({'_id':2},{'$addToSet':{'urls':'http://www.openstack.org'}}) db.urls.update({'_id':2},{'$addToSet':{'urls':'http://www.openstack.org'}}) db.urls.update({'_id':2},{'$addToSet':{'urls':'http://www.python.org'}}) # 然后再来查看 发现id为1的文档对象中的urls对应的数组只有http://www.baidu.com
而id为2的文档对象的urls对应的数组中有"http://www.openstack.org", "http://www.python.org" 这就是$addToSet的作用 > db.urls.find() { "_id" : 1, "urls" : [ "http://www.baidu.com" ] } { "_id" : 2, "urls" : [ "http://www.openstack.org", "http://www.python.org" ] } # 如果我们使用$each来批量添加域名,最终的结果也不会重复 db.urls.update({'_id':1},{ '$addToSet':{ 'urls':{ '$each':['www.openstack.org','www.openstack.org','http://www.xxx.com'] } } }) db.urls.update({'_id':2},{ '$addToSet':{ 'urls':{ '$each':['www.openstack.org','www.openstack.org','http://www.xxx.com'] } } }) 最后再来查询下: > db.urls.find() { "_id" : 1, "urls" : [ "http://www.baidu.com", "www.openstack.org", "http://www.xxx.com" ] } { "_id" : 2, "urls" : [ "http://www.openstack.org", "http://www.python.org", "www.openstack.org", "http://www.xxx.com" ] } > 注意http://www.openstack.org和www.openstack.org是两个不同的域名,不要搞混淆了

6.删除元素

#=======>6、删除元素 如果把数组看成是队列或者栈,可以用"$pop",这个修改器可以从数组任何一端删除元素。 {"$pop":{"key":1}} 从数组末尾删除一个元素 {"$pop":{"key":-1}} 从头部删除 > db.queue.insert({'_id':1,'queue':[]}) WriteResult({ "nInserted" : 1 }) # 入队列 db.queue.update({'_id':1},{'$push':{'queue':'alex'}}) db.queue.update({'_id':1},{'$push':{'queue':'egon'}}) db.queue.update({'_id':1},{'$push':{'queue':'wxx'}}) db.queue.update({'_id':1},{'$push':{'queue':'yxx'}}) > db.queue.find() { "_id" : 1, "queue" : [ "alex", "egon", "wxx", "yxx" ] } # 出队列 db.queue.update({'_id':1},{"$pop":{"queue":-1}}) db.queue.update({'_id':1},{"$pop":{"queue":-1}}) db.queue.update({'_id':1},{"$pop":{"queue":-1}}) # 最终打印结果,可以发现这里出队列是从头部逐个删除元素 > db.queue.find() { "_id" : 1, "queue" : [ "yxx" ] } # 我们再来新增id为2的文档对象记录: db.queue.insert({'_id':2,'queue':[]}) db.queue.update({'_id':2}, {'$push':{'queue': 'carson01'}}) db.queue.update({'_id':2}, {'$push':{'queue': 'carson02'}}) db.queue.update({'_id':2}, {'$push':{'queue': 'carson03'}}) # "$pull" 把符合条件的统统删掉,而$pop只能按照位置删除 db.queue.update({'_id':2},{"$pull":{"queue":'carson'}}) > db.queue.find() { "_id" : 1, "queue" : [ "yxx" ] } { "_id" : 2, "queue" : [ "carson01", "carson02", "carson03" ] }

7.基于数组位置的修改器

#=======>7、基于位置的数组修改器 db.blogcomment.insert({'_id':1,'name':'alex意外死亡的真相'}) db.blogcomment.update({'_id':1},{'$push':{'comments':{"name":"egon","content":'alex是谁???','thumb':20}}}) db.blogcomment.update({'_id':1},{'$push':{'comments':{"name":"wxx","content":'我去,真的假的','thumb':30}}}) db.blogcomment.update({'_id':1},{'$push':{'comments':{"name":"yxx","content":'吃喝嫖赌抽,欠下两个亿','thumb':40}}}) > db.blogcomment.find().pretty() { "_id" : 1, "name" : "alex意外死亡的真相", "comments" : [ { "name" : "egon", "content" : "alex是谁???", "thumb" : 20 }, { "name" : "wxx", "content" : "我去,真的假的", "thumb" : 30 }, { "name" : "yxx", "content" : "吃喝嫖赌抽,欠下两个亿", "thumb" : 40 } ] } 根据下标修改 db.blogcomment.update({'_id':1},{'$set':{'comments.0.thumb':666}}) # 然后再来查询下: > db.blogcomment.find().pretty() { "_id" : 1, "name" : "alex意外死亡的真相", "comments" : [ { "name" : "egon", "content" : "alex是谁???", "thumb" : 666 # 变成了666,原来是20 }, { "name" : "wxx", "content" : "我去,真的假的", "thumb" : 30 }, { "name" : "yxx", "content" : "吃喝嫖赌抽,欠下两个亿", "thumb" : 40 } ] } 使用$,$代表根据条件匹配出的元素 相当于$代表的是前面匹配出的某条文档对象,例如我们通过'comments.name':'wxx' 可以匹配出的文档对象为 { "name" : "wxx", "content" : "我去,真的假的", "thumb" : 30 } 此时$就代表匹配出的这个文档对象,然后通过.的方式来修改该文档对象的thumb属性值 db.blogcomment.update({'comments.name':'wxx'},{'$set':{'comments.$.thumb':999}}) > db.blogcomment.find().pretty() { "_id" : 1, "name" : "alex意外死亡的真相", "comments" : [ { "name" : "egon", "content" : "alex是谁???", "thumb" : 666 }, { "name" : "wxx", "content" : "我去,真的假的", "thumb" : 999 }, { "name" : "yxx", "content" : "吃喝嫖赌抽,欠下两个亿", "thumb" : 40 } ] } >

接着来看查询操作:

# SQL:=,!=,>,<,>=,<= # MongoDB:{key:value}代表什么等于什么,"$ne","$gt","$lt","gte","lte",其中"$ne"能用于所有数据类型,其表示不等于 #1select * from db1.user where name = "alex"; db.user.find({'name':'alex'}) #2select * from db1.user where name != "alex"; db.user.find({'name':{"$ne":'alex'}}) #3select * from db1.user where id > 2; db.user.find({'_id':{'$gt':2}}) #4select * from db1.user where id < 3; db.user.find({'_id':{'$lt':3}}) #5select * from db1.user where id >= 2; db.user.find({"_id":{"$gte":2,}}) #6select * from db1.user where id <= 2; db.user.find({"_id":{"$lte":2}})

我们以集合users为例来练习几个上面的示例:

找出users集合中age>=30,<=50的文档对象 db.users.find({"age":{"$gte":30, "$lte":50}})

接下来我们看看MongoDB中的逻辑运算:

# SQL:and,or,not # MongoDB:字典中逗号分隔的多个条件是and关系"$or"的条件放到[]内,"$not" #1select * from db1.user where id >= 2 and id < 4; db.user.find({'_id':{"$gte":2,"$lt":4}}) #2select * from db1.user where id >= 2 and age < 40; db.user.find({"_id":{"$gte":2},"age":{"$lt":40}}) #3select * from db1.user where id >= 5 or name = "alex"; db.user.find({ # or的条件放到数组内 "$or":[ {'_id':{"$gte":5}}, {"name":"alex"} ] }) # 取出id值与2取余为1的文档对象 #4select * from db1.user where id % 2=1; db.user.find({'_id':{"$mod":[2,1]}}) #5、上题,取反 db.user.find({'_id':{"$not":{"$mod":[2,1]}}})

成员匹配in和not in:

# SQL:in,not in # MongoDB:"$in","$nin" #1select * from db1.user where age in (20,30,31); db.user.find({"age":{"$in":[20,30,31]}}) #2select * from db1.user where name not in ('alex','yuanhao'); db.user.find({"name":{"$nin":['alex','yuanhao']}})

MongoDB中的正则表达式匹配:

# SQL: regexp 正则 # MongoDB: /正则表达/i #1select * from db1.user where name regexp '^j.*?(g|n)$'; db.user.find({'name':/^j.*?(g|n)$/i})

例如找到userinfo表中name以c开头的姓名:

> db.userinfo.find({'name':/^c.*?/i}) { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "name" : "carson", "is_nb" : true, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b7"), "name" : "carson666", "is_sb" : false, "hobbies" : [ "music", "read", "dancing" ] } >

获取集合中文档对象的指定字段:

#1select name,age from db1.user where id=3; db.user.find({'_id':3},{'_id':0,'name':1,'age':1})

记住,一旦涉及到条件的筛选,那就需要单独将条件表达式写到一个字典中:{'id':3}

查询数组,首先修改我们原始的userinfo集合如下:

> db.userinfo.find() { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "name" : "carson", "is_nb" : true, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b5"), "name" : "tom", "is_sb" : true, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b6"), "name" : "eva", "is_sb" : "wxx", "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b7"), "name" : "carson666", "is_sb" : false, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b8"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b9"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c6a6e8c6f3bc41b4589ba"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c837a8c6f3bc41b4589bb"), "name" : "angina", "age" : 10 } { "_id" : ObjectId("5a5c837a8c6f3bc41b4589bc"), "name" : "angina", "age" : 20 } { "_id" : ObjectId("5a5c837b8c6f3bc41b4589bd"), "name" : "angina", "age" : 30 } # 修改name为carson的文档对象对应的hobbies > db.userinfo.update({'name':'carson'},{"hobbies": ["tea", "singing"]}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.userinfo.find() { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "hobbies" : [ "tea", "singing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b5"), "name" : "tom", "is_sb" : true, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b6"), "name" : "eva", "is_sb" : "wxx", "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b7"), "name" : "carson666", "is_sb" : false, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b8"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b9"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c6a6e8c6f3bc41b4589ba"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c837a8c6f3bc41b4589bb"), "name" : "angina", "age" : 10 } { "_id" : ObjectId("5a5c837a8c6f3bc41b4589bc"), "name" : "angina", "age" : 20 } { "_id" : ObjectId("5a5c837b8c6f3bc41b4589bd"), "name" : "angina", "age" : 30 } # 修改name为tom的文档对象对应的hobbies > db.userinfo.update({'name':'tom'},{"hobbies": ["music", "read", "dancing","tea"]}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.userinfo.update({'name':'eva'},{"hobbies": [tea",]})
> db.userinfo.update({'name':'eva'},{"hobbies": ["tea",]}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.userinfo.find() { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "hobbies" : [ "tea", "singing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b5"), "hobbies" : [ "music", "read", "dancing", "tea" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b6"), "hobbies" : [ "tea" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b7"), "name" : "carson666", "is_sb" : false, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b8"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b9"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c6a6e8c6f3bc41b4589ba"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c837a8c6f3bc41b4589bb"), "name" : "angina", "age" : 10 } { "_id" : ObjectId("5a5c837a8c6f3bc41b4589bc"), "name" : "angina", "age" : 20 } { "_id" : ObjectId("5a5c837b8c6f3bc41b4589bd"), "name" : "angina", "age" : 30 }

查找方法

> db.users.find({"age":{"$gt":30}}) { "_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "age" : 111 } { "_id" : ObjectId("5a5c83c48c6f3bc41b4589bf"), "name" : "angina", "age" : 222, "addr" : { "country" : "China", "city" : "BJ" } } { "_id" : ObjectId("5a5c854e8c6f3bc41b4589c1"), "name" : "angina", "age" : 40 } { "_id" : ObjectId("5a5c856d8c6f3bc41b4589c2"), "name" : "angina", "age" : 50, "addr" : { "country" : "China", "city" : "BJ" } } # 和上面的对比,查找匹配成功的第一条 > db.users.findOne({"age":{"$gt":30}}) { "_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "age" : 111 } >

 删除集合中的文档对象

> db.userinfo.find() { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "hobbies" : [ "tea", "singing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b5"), "hobbies" : [ "music", "read", "dancing", "tea" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b6"), "hobbies" : [ "tea" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b7"), "name" : "carson666", "is_sb" : false, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b8"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b9"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c6a6e8c6f3bc41b4589ba"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c837a8c6f3bc41b4589bb"), "name" : "angina", "age" : 10 } { "_id" : ObjectId("5a5c837a8c6f3bc41b4589bc"), "name" : "angina", "age" : 20 } { "_id" : ObjectId("5a5c837b8c6f3bc41b4589bd"), "name" : "angina", "age" : 30 } #删除匹配到的多个文档对象中第一个,发现id为"5a5c6a6c8c6f3bc41b4589b8"这条文档对象没有了 > db.userinfo.deleteOne({'name':"angina"}) { "acknowledged" : true, "deletedCount" : 1 } > db.userinfo.find() { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "hobbies" : [ "tea", "singing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b5"), "hobbies" : [ "music", "read", "dancing", "tea" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b6"), "hobbies" : [ "tea" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b7"), "name" : "carson666", "is_sb" : false, "hobbies" : [ "music", "read", "dancing" ] } { "_id" : ObjectId("5a5c6a6c8c6f3bc41b4589b9"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c6a6e8c6f3bc41b4589ba"), "name" : "angina", "age" : 21 } { "_id" : ObjectId("5a5c837a8c6f3bc41b4589bb"), "name" : "angina", "age" : 10 } { "_id" : ObjectId("5a5c837a8c6f3bc41b4589bc"), "name" : "angina", "age" : 20 } { "_id" : ObjectId("5a5c837b8c6f3bc41b4589bd"), "name" : "angina", "age" : 30 } # 删除匹配到的文档对象中的多条记录,可以发现name为angina的所有文档记录都没有了 > db.userinfo.deleteMany({'name':"angina"}) { "acknowledged" : true, "deletedCount" : 5 } > db.userinfo.find() { "_id" : ObjectId("5a5c5fb18c6f3bc41b4589b4"), "hobbies" : [ "tea", "singing" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b5"), "hobbies" : [ "music", "read", "dancing", "tea" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b6"), "hobbies" : [ "tea" ] } { "_id" : ObjectId("5a5c60028c6f3bc41b4589b7"), "name" : "carson666", "is_sb" : false, "hobbies" : [ "music", "read", "dancing" ] } # 删除集合中的所有文档对象,相当于关系型数据库中的表操作:truncate emp; > db.userinfo.deleteMany({}) { "acknowledged" : true, "deletedCount" : 4 } > db.userinfo.find() >

排序显示:

> db.users.find() { "_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "name" : "carson666" } { "_id" : ObjectId("5a5c83c48c6f3bc41b4589bf"), "name" : "alex" } { "_id" : ObjectId("5a5c83c58c6f3bc41b4589c0"), "name" : "carson" } { "_id" : ObjectId("5a5c854e8c6f3bc41b4589c1"), "name" : "angina", "age" : 40 } { "_id" : ObjectId("5a5c856d8c6f3bc41b4589c2"), "name" : "tom" } # 按照name升序显示 > db.users.find().sort({"name":1}) { "_id" : ObjectId("5a5c83c48c6f3bc41b4589bf"), "name" : "alex" } { "_id" : ObjectId("5a5c854e8c6f3bc41b4589c1"), "name" : "angina", "age" : 40 } { "_id" : ObjectId("5a5c83c58c6f3bc41b4589c0"), "name" : "carson" } { "_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "name" : "carson666" } { "_id" : ObjectId("5a5c856d8c6f3bc41b4589c2"), "name" : "tom" } # 按照name降序显示 > db.users.find().sort({"name":-1}) { "_id" : ObjectId("5a5c856d8c6f3bc41b4589c2"), "name" : "tom" } { "_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "name" : "carson666" } { "_id" : ObjectId("5a5c83c58c6f3bc41b4589c0"), "name" : "carson" } { "_id" : ObjectId("5a5c854e8c6f3bc41b4589c1"), "name" : "angina", "age" : 40 } { "_id" : ObjectId("5a5c83c48c6f3bc41b4589bf"), "name" : "alex" }

分页显示

# 分页:--limit代表取多少个document,skip代表跳过前多少个document。 按照name进行升序排列 > db.users.find().sort({"name":1}) { "_id" : ObjectId("5a5c83c48c6f3bc41b4589bf"), "name" : "alex" } { "_id" : ObjectId("5a5c854e8c6f3bc41b4589c1"), "name" : "angina", "age" : 40 } { "_id" : ObjectId("5a5c83c58c6f3bc41b4589c0"), "name" : "carson" } { "_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "name" : "carson666" } { "_id" : ObjectId("5a5c856d8c6f3bc41b4589c2"), "name" : "tom" } 现在我们使用分页显示,首先是按照name升序排列,然后跳过前面2个文档对象,接着取出3个文档对象 > db.users.find().sort({'name':1}).limit(3).skip(2) { "_id" : ObjectId("5a5c83c58c6f3bc41b4589c0"), "name" : "carson" } { "_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "name" : "carson666" } { "_id" : ObjectId("5a5c856d8c6f3bc41b4589c2"), "name" : "tom" } 我们来看看使用下面的表达式会怎么样: > db.users.find().sort({'name':1}).skip(2).limit(3) { "_id" : ObjectId("5a5c83c58c6f3bc41b4589c0"), "name" : "carson" } { "_id" : ObjectId("5a5c83c48c6f3bc41b4589be"), "name" : "carson666" } { "_id" : ObjectId("5a5c856d8c6f3bc41b4589c2"), "name" : "tom" } 结果和上面一样的,最后来看看下面的: 跳过排好序的文档对象中的2个,接着取一个出来 > db.users.find().sort({'name':1}).limit(1).skip(2) { "_id" : ObjectId("5a5c83c58c6f3bc41b4589c0"), "name" : "carson" } > db.users.find().sort({'name':1}).skip(2).limit(1) { "_id" : ObjectId("5a5c83c58c6f3bc41b4589c0"), "name" : "carson" }

获取数量:调用count()方法

# 查询名字以c开头的文档对象的个数 > db.users.count({'name':/^c.*?/i}) 2
> db.users.find({'name':/^c.*?/i}).count() 2

Null值的匹配:

db.t2.insert({'a':10,'b':111}) db.t2.insert({'a':20}) db.t2.insert({'b':null}) db.t2.insert({'c':110, 'b':112, 'd':null}) db.t2.insert({'e': 12}) db.t2.insert({'spark': 666,'carson':999}) > db.t2.find() { "_id" : ObjectId("5a5da18cbb7aac032e104be1"), "a" : 10, "b" : 111 } { "_id" : ObjectId("5a5da18cbb7aac032e104be2"), "a" : 20 } { "_id" : ObjectId("5a5da18cbb7aac032e104be3"), "b" : null } { "_id" : ObjectId("5a5da1f1bb7aac032e104be4"), "c" : 110, "b" : 112, "d" : null } { "_id" : ObjectId("5a5da1f2bb7aac032e104be5"), "e" : 12 } { "_id" : ObjectId("5a5da248bb7aac032e104be6"), "spark" : 666, "carson" : 999 } """ 从结果可以看出来,{'key':null} 表示匹配key的值为null或者没有这个key,可以看到匹配的文档对象中 要么没有b这个key,例如 "a" : 20和"e" : 12"spark" : 666, "carson" : 999, 要么b这个key的值就是null """ > db.t2.find({'b':null}) { "_id" : ObjectId("5a5da18cbb7aac032e104be2"), "a" : 20 } { "_id" : ObjectId("5a5da18cbb7aac032e104be3"), "b" : null } { "_id" : ObjectId("5a5da1f2bb7aac032e104be5"), "e" : 12 } { "_id" : ObjectId("5a5da248bb7aac032e104be6"), "spark" : 666, "carson" : 999 }