MongoDB 学习笔记(二):shell中执行增删查改

一、查

1、查询集合中所有文档:db.集合名.find()

2、查询集合中第一个文档:db.集合名.findOne()

3、指定查询条件:第一个参数就是指定查询条件,注意:查询文档中“键值对”中的值必须为常量

  • 查询全部文档:db.集合名.find({}),如下图:如果查询文档{}中包含了多个键值对,则是AND的关系。

        MongoDB 学习笔记(二):shell中执行增删查改_第1张图片

  • 五种基本的查询条件:$lt(<)、$lte(<=)、$gt(>)、$gte(>=)、$ne(!=),如下图:从第一个实验可以发现,当对某个key,该key的value中同时指定了多个查询条件,这些查询条件的关系是“与”关系;但是从第二个和第三个实现中可以发现,当对某个key,分开指定了多次查询条件,则对该key的查询条件是以最后一个查询条件为准。

        MongoDB 学习笔记(二):shell中执行增删查改_第2张图片

  • 包含与不包含:$in、$nin,都只能作用于数组,而不能作用于其他类型,如下图:

        MongoDB 学习笔记(二):shell中执行增删查改_第3张图片

  • or查询:$or,如下图:注意最外面是or查询器,or查询器的value是一个数组,里面是很多的查询条件,数组中每个查询条件就是or的关系。使用这个条件操作符有一个最佳实践是:将最宽松的条件放在前面,这样可以加快文档匹配速度

        MongoDB 学习笔记(二):shell中执行增删查改_第4张图片

  • null查询:如下图

        MongoDB 学习笔记(二):shell中执行增删查改_第5张图片

        会查询出没有这个key的记录,如果需要过滤掉这种文档,需要另外一个条件操作符$exists,指明这个键必须存在,如下如:此时“=null”的判断只能通过{"$in":[null]}来实现了

        MongoDB 学习笔记(二):shell中执行增删查改_第6张图片

  • 正则查询:Shell中写正则表达式的方式和JavaScript的一致,写在一对“ // ”之间的就是正则表达式。查询name这个key对应的value中包含有字母a的文档,如下图:

        MongoDB 学习笔记(二):shell中执行增删查改_第7张图片

        MongoDB支持正则表达式这种数据类型,对于这种键值对,正则表达式也可以匹配成功,如下图:还可以发现正则匹配不区分大小写。但注意正则表达式的匹配必须是完全匹配,即正则表达式的写法完全相同才可以匹配成功。MongoDB         可以为前缀型的正则表达式(/^abc/i)查询使用索引,所以这种前缀型的正则表式查询速度会很快。

        MongoDB 学习笔记(二):shell中执行增删查改_第8张图片

  • $not:可以用到任何地方进行取反的操作,与$nin的区别就在于$nin只能用在数组上,如下图:

        MongoDB 学习笔记(二):shell中执行增删查改_第9张图片

  • 数组查询$all与index的应用:

        查询出books这个key对应的value中(对应类型是数组)同时存在“JS”与“JSP”这两个元素的文档,如下图:使用“$all”对数组内元素的顺序没有要求,只要全部包含的数组都能查询出来

        MongoDB 学习笔记(二):shell中执行增删查改_第10张图片

        查询出books这个key对应的value中(对应类型是数组)第2个元素是“JS”的文档,如下图:注意,使用到了“.”的形式,需要加上引号

        MongoDB 学习笔记(二):shell中执行增删查改_第11张图片

  • $size:查询指定长度的数组,不能和其他操作符连用。查询出books这个key对应的value中(对应类型是数组)元素个数为1的文档,如下图:

        MongoDB 学习笔记(二):shell中执行增删查改_第12张图片

  • 查询出某个文档中某个key(假设类型是数组)的元素个数,如下图:使用find查询出来的结果由于结果集的数量不定,所以查询出来的不的一个对象,是一个游标,所以需要用到游标遍历的方式来遍历查询出来的每个对象,而findOne就可以直接输出。

        MongoDB 学习笔记(二):shell中执行增删查改_第13张图片

  • 数组查询:对于数组可以这样理解:数组中每一个元素都是这个键值对键的一个有效值,集合中的文档有一个key,是数组类型,数组中每个元素又是一个简单类型的数据,如下图:

        MongoDB 学习笔记(二):shell中执行增删查改_第14张图片

        发现只要books这个键对应的值包含元素JS的数组都能被查询出来。也可以使用精确匹配的方式,即查询条件文档中键值对的值也是数组,如下图:可以发现使用精确查询时,MongoDB的处理方式是完全相同的匹配,个数和顺序必须完          全一样才能查询出来。

       MongoDB 学习笔记(二):shell中执行增删查改_第15张图片

        集合中的文档有一个key,是数组类型,数组中每个元素又是一个对象,如下图:所以,内嵌文档的完全匹配查询和数组的完全匹配查询一样,内嵌文档内键值对的数量,顺序都必须一致才会匹配

        MongoDB 学习笔记(二):shell中执行增删查改_第16张图片

        如上图所示,查询条件是数组元素,这里没有使用任何额外的查询符,当查询条件与数组中元素(对象)完全匹配且顺序一致时才能查询出来。为了解决这个问题,可以使用“.”的方式,如下图:

        MongoDB 学习笔记(二):shell中执行增删查改_第17张图片

        这样就解决了顺序问题和完全匹配的问题,但是这里会有个问题存在,如下图:

        MongoDB 学习笔记(二):shell中执行增删查改_第18张图片

        其中courses.score:95满足文档中courses这个key的value中的第二个元素,而courses.course:Math满足文档中courses这个key的value中的第一个元素,因为这里的每个查询条件都会被MongoDB进行遍历查询,只要其中有个元素满足了第一个查询条件,再接着按第二个查询条件查询,然后再有任一个元素满足就算查询成功。所以为了解决这样的问题,可以使用条件组合查询符$elemMatch,它能同时解决以上存在的全部问题,如下图:把条件当成一个组合进行查询,

        只有当一个文档的满足这个组合条件才算查询成功。

        MongoDB 学习笔记(二):shell中执行增删查改_第19张图片

  • $where查询:在一些比较复杂的查询中使用$where查询很方便,但是$where查询存在一个性能问题,应该少用,如下图:查询年龄为22岁,有JS这本书且选修了Math这门课程的文档。

        MongoDB 学习笔记(二):shell中执行增删查改_第20张图片

        MongoDB在查询时,会将每个文档转换成一个javascript对象,然后扔到这个函数中去执行,通过返回结果来判断其是否匹配。在实际使用中,尽量避免使用”$where" 条件操作符,因为其性能很差。如果不可避免,则尽量这样写:                     find({”other“:”......“,......,“$where”:""}),即将"$where"放最后,作为结果调优,让常规查询作为前置过滤条件,这样能减少一些性能损失。

  • $mod:使用格式为 {"键":{"$mod":[num1, num2]}},查询“键”的值对num1取余,如果余等于num2,则整条文档符合条件,如下图:
         MongoDB 学习笔记(二):shell中执行增删查改_第21张图片

4、查询指定key:第二个参数就是指定要查询的key,如下图:想要查询出哪个key,就将其对应的value置为非0,默认情况下会将_id也查询出来,可以将其对应的value置为0,就不会查询出来了。

MongoDB 学习笔记(二):shell中执行增删查改_第22张图片

如上图中最后一个列子,既指定了要查询的name这个key,又指定了不查询的_id这个key,这里包含了要查询的key和要排除的key,但是在其他情况下不能混合使用,要么指定要查询的key,要么指定要排除的key,如下图:

MongoDB 学习笔记(二):shell中执行增删查改_第23张图片

如果指定的是要排序的键,此时如果也指明了_id键,则_id必须指定为0,如下如:

MongoDB 学习笔记(二):shell中执行增删查改_第24张图片

如果对同一个key指定了两次,则以最后一次为准,如下图:

MongoDB 学习笔记(二):shell中执行增删查改_第25张图片

如果一个key是数组类型,还可以用$slice操作符指定显示的数组元素,如下图:前面几个都是指定从哪个数组元素索引开始,取多少个元素,而最后2个是选取最前面和最后2个元素。

MongoDB 学习笔记(二):shell中执行增删查改_第26张图片

如果第二个参数中有个键使用了条件操作符"$slice",则默认查询会返回所有的键,如果此时要忽略一些键,可以手动指明。

5、find函数和findOne函数的区别,对于一些可以接受文档做参数的函数如insert,可以直接使用findOne的返回值作为参数。

二、增

1、添加集合并插入一个文档:db.集合名.insert({...})

如下图:如果person集合不存在,则会为当前数据库添加一个名为“person”的集合,然后为该集合插入一个文档。

注意:MongoDB会自动为该文档加入一个“_id”的key,但是如果要插入的文档中已经包含了"_id"的key,则不会再自动添加了,如下:

以上执行insert时候传入的是一个对象,那么传入的是一个对象数组呢?如下图:如果插入时传入的是一个对象数组,那么会为该对象数组中的每一个对象插入一个文档。

MongoDB 学习笔记(二):shell中执行增删查改_第27张图片

2、批量插入

MongoDB支持并推荐更高效的批量插入,一次批量插入只会发送一个TCP请求,一个头部信息,所以比挨个单条插入要快很多。要完成批量插入可以用MongoDB的应用驱动,Shell中是不支持批量插入的,只能使用for循环来模拟,如下图:

MongoDB 学习笔记(二):shell中执行增删查改_第28张图片

3、save与insert操作

当执行insert操作时,如果待插入的文档的“_id”这个key的值已经存在了(字面值一样且类型一样),则会报错,如下图

MongoDB 学习笔记(二):shell中执行增删查改_第29张图片

但是如果采用save方法遇到已经存在的"_id",则不会报错,它其实是把已经存在的“_id”的那个文档进行更新;当然,如果要插入的文档的"_id"值还不存在则插入新文档就是,如下图:总结save函数就是如果该函数参数的那个文档包含“_id”键,则save函数其实会转调upsert,如果文档中不存在"_id"键,save函数默认就是向集合中插入一条文档

MongoDB 学习笔记(二):shell中执行增删查改_第30张图片

三、删

1、删除集合中所有文档:db.集合名.remove(),集合本身和索引不会被删除。

2、根据条件删除:db.集合名.remove({...}),如下图:name为“eee”的全部被删除了。

MongoDB 学习笔记(二):shell中执行增删查改_第31张图片

3、remove方法会删除文档,但不会影响到集合本身,集合上建立的索引也会保留。如果要删除整个集合内容,还可以考虑直接删除集合,这样会更高效并且将所有索引也会一起删除。调用db.集合名.help() 查看Shell中为集合提供的所有函数,发现其有一个drop函数,用于删除当前的集合,如下图:


四、改

1、强硬的文档替换式更新

此种更新操作类似于把之前的老文档删除,然后替换为更新的文档,也就是用新文档替换老文档,如下图:原文档中根本不存在age这个key,但是执行替换式更新后,不管老文档存在哪些key,更新最后都仅仅只会存在新的文档中的那些key(原文档的_id还会存在)。

MongoDB 学习笔记(二):shell中执行增删查改_第32张图片

这个时候如果是真的只需要更新name键的值,可以使用如下的方式:但是这种方式要注意一个问题,就是变量p必须通过findOne()去获得,如果通过find()方法获得,则后面的update方法会报错;而且因为findOne方法仅会返回查询文档匹配的一条集合文档,使用这种方式做update时,此处update满足更新条件的文档可能不止一条,那么更新就会失败,因为会出现集合中"_id"键值重复的现象。

MongoDB 学习笔记(二):shell中执行增删查改_第33张图片

不可以更新“_id”这个key的值,而不管更新后的“_id”值是否已经存在,如下图:

MongoDB 学习笔记(二):shell中执行增删查改_第34张图片

当满足更新条件的文档不止一个时,MongoDB只会更新第一个文档,如下图:

MongoDB 学习笔记(二):shell中执行增删查改_第35张图片

当没有任何文档满足更新条件时,以上这些更新都不会进行任何的更新;只有当满足更新条件时才会进行更新,如果没有满足更新条件的文档,要进行插入操作呢?那么可以使用update方法的第三个参数,如下:这称为upsert操作,upsert的操作是原子性的

MongoDB 学习笔记(二):shell中执行增删查改_第36张图片

2、使用修改器进行局部更新

2.1、$set修改器:{$set:{key:value}},如果满足更新条件的文档中存在$set修改器中的key时,则进行更新,否则进行添加,如下图:还是只会对满足条件的第一个文档进行更新

MongoDB 学习笔记(二):shell中执行增删查改_第37张图片

2.2、$inc修改器:{$inc:{key:value}},仅适用于数字类型,可以为指定的key对应的数字类型的值进行加减操作,如下图:

MongoDB 学习笔记(二):shell中执行增删查改_第38张图片

upsert操作结合$inc修改器使用,如下:注意结果是20,而不是10

MongoDB 学习笔记(二):shell中执行增删查改_第39张图片

2.3、$unset修改器:{$unset:{key:value}},删除指定的key,如下图:

MongoDB 学习笔记(二):shell中执行增删查改_第40张图片

2.4、$push修改器:{$push:{key:value}},如果指定的key是数组,则往该数组中追加新的元素;如果指定的key不是数组,则中断操作;如果不存在指定的key,则创建,且类型为数组类型,并加入新的元素;如下图:

MongoDB 学习笔记(二):shell中执行增删查改_第41张图片

2.5、$pushAll修改器:{$pushAll:{key:value}},与$push一样,只是它可以一次性批量加入一个数组中的所有元素,如下图:

MongoDB 学习笔记(二):shell中执行增删查改_第42张图片

2.6、$addToSet修改器:{$addToSet:{key:value}},与$push一样,只是当目标数组不存在该元素时才加入,如下图:

MongoDB 学习笔记(二):shell中执行增删查改_第43张图片

可以使用查询器$ne与修改器$push实现$addToSet修改器的功能,如下图:修改器“$ne”在这里的作用是如果键对应的值中不包含修改器指定的值,则往这个键对应的数组中push这个值进去

MongoDB 学习笔记(二):shell中执行增删查改_第44张图片

2.7、$pop修改器:{$pop:{key:value}},从指定数组的头或尾删除一个元素,从头删除一个元素用小于0的值,从尾删除一个元素用大于0的值,如下图:

MongoDB 学习笔记(二):shell中执行增删查改_第45张图片

2.8、$pull修改器:{$pull:{key:value}},从指定数组中删除一个被指定的值,如下图:

MongoDB 学习笔记(二):shell中执行增删查改_第46张图片

2.9、$pullAll修改器:{$pullAll:{key:value}},从指定数组中一次性删除多个被指定的值,如下图:

MongoDB 学习笔记(二):shell中执行增删查改_第47张图片

2.10、数组定位器$:如果数组中有多个元素,需要对其中一部分进行更新,则可以使用定位器$。如下图:可以发现它还是只会对该文档中books那个数组中满足条件的第一个元素其作用,且注意:当使用了books.price这种方式时,一定要加上引号,不然会报错。

MongoDB 学习笔记(二):shell中执行增删查改_第48张图片

如果是知道数组元素索引,还可以通过索引的方式,比如把上面的books.$.author改为:books.0.author。

2.11、$addToSet与$each结合完成批量数组更新,如下图:$each会循环后面的数组,把每个元素值进行$addToSet操作。

MongoDB 学习笔记(二):shell中执行增删查改_第49张图片

2.12、$push与$inc结合使用:比如要往文档的books这个key(数组)中加入一个元素,同时该文档的books_size这个key的大小加1,如下图:这个方式和修改器"$addToSet"没法配合使用,因为无法判断这个元素是否添加到了数组中

MongoDB 学习笔记(二):shell中执行增删查改_第50张图片

3、批量更新

通过上面的实验可以发现以上的更新全部都只是会对满足更新条件的第一个文档进行更新,如果要对满足条件的所有文档进行批量更新则可以使用update的第四个参数,且这个参数要配合到修改器一起才会生效,强硬式替换更新无法进行批量操作,如下图:

MongoDB 学习笔记(二):shell中执行增删查改_第51张图片

 

MongoDB 学习笔记(二):shell中执行增删查改_第52张图片

4、其他用法

该可以先将满足条件的文档查询出来,并赋值给一个变量,然后再进行更新,如下:

MongoDB 学习笔记(二):shell中执行增删查改_第53张图片

5、文档内存分配与更新效率

一些修改器,比如“$inc”能就地修改文档,不会引起文档大小的变化,所以操作会很快。而数组类型的修改器操作后可能引起文档大小的变化,则速度会慢,否则操作很快。当一个文档被创建的时候,MongoDB为其分配内存和预留内存,用来适应文档大小的变化,当更新操作不超过预留内存时速度非常快,但是当超过了预留内存后就要分配新的内存,所以会消耗时间,速度慢些。如下图:

MongoDB 学习笔记(二):shell中执行增删查改_第54张图片

6、MongoDB会保证更新操作是原子性的,如果两个客户端对同一条文档进行更新,请求先到达的先执行,然后另一个更新请求再执行。

7、在MongoDB Shell中执行完任何命令,都可以再通过运行getLastError命令来查看上次执行的命令影响了多少条文档,如下图:“键”n的值就是上次操作影响的文档条数。

MongoDB 学习笔记(二):shell中执行增删查改_第55张图片

五、其它函数

1、runCommand函数:可以执行MongoDB中的一些特殊函数。

2、findAndModify函数:它就是MongoDB中的一个特殊函数,用于返回更新前或后的文档,或者是删除的文档。它执行起来有些慢,因为它要等待数据库的响应后再返回,大概耗时相当于一次查找,一次更新和一次getLastError顺序执行所需的时间(和普通的更新操作不同,其他更新操作都是瞬间完成的)。但是对于操作查询以及执行其它需要取值和赋值风格的原子性操作来说是很方便的。该函数中每个键对应的值如下:

  • findAndModify:一个集合名,必须用引号括起来。
  • query:查询文档,用作检索文档的条件。
  • sort:排序结果的条件。它只会作用在一条文档上,如果匹配了多条,按这个排序,取第一条进行更新。
  • update:修改器文档,对所找到的文档执行更新。
  • remove:布尔类型,表示是否删除文档。
  • new:布尔类型,表示返回的是更新前的文档还是更新后的文档,默认是更新前的文档。true表示修改后的。
  • 说明:update和remove中必须有且仅有一个。要是匹配不到文档,则不会执行任何操作。
  • 限制:该函数一次只能处理一个文档,所以只能更新或删除满足条件的第一个文档。也不能执行upsert操作,只能更新已有文档。

如下图:

MongoDB 学习笔记(二):shell中执行增删查改_第56张图片

六、瞬间完成

插入,删除,更新(除了findAndModify命令),都是瞬间完成的,就是客户端发送命令后,即刻返回,不会等待数据库返回任何操作结果或抛出异常。这种方式最大的好处就是快,对于处理一些对数据完整性要求不是很高的大数据量操作是特别适合的。但对于一些对安全要求较高的数据库操作就不能依赖瞬间完成了,在一次数据库操作后,就必须执行一个"getLastError"命令,来看看本次操作的结果,结果中包含是否成功,如果失败,还会包含异常原因。这种安全操作的后果就是性能的损失,操作后必须等待数据库的响应。

七、请求和连接

MongoDB会为每一个数据库连接创建一个请求队列,客户端发送的请求都会先放到这个队列中(对于“瞬间完成”的请求会直接返回),MongoDB会从队列中挨个取出请求来执行。对于同一个连接,前面请求的操作结果对后面请求是可见的。

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(mongodb)