良许Linux教程网 干货合集 详解MongoDB中的CRUD操作

详解MongoDB中的CRUD操作

MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。

MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型,本篇文章重点为大家讲解一下MongoDB的CRUD操作。

详解MongoDB中的CRUD操作

INSERT操作

MongoDB中的新增操作,把一个新的Document插入到一个Collection中。

如果该Collection不存在,则新增一个新的Collection。这个和关系数据库有很大的区别,在关系数据库中,我们需要定义数据库的schema和表结构,这是NoSQL(MongoDB是NoSQL的一种)数据库和关系数据库很大的区别。在MongoDB中,我们可以在一个Collection中包含多个不同结构的Document(不推荐这样做,一个Collection最好具有相同格式的Document,便于维护和使用)。

关于”*id”字段,当我们新增一个Document到Collection中的时候,MongoDB需要每一个新增的Document中有一个”*id”字段,MongoDB把这个字段作为主键,所以要求这个字段在Collection中是唯一的。如果新增的Document中没有包含”*id”字段,那么MongoDB的客户端会在该Document中新增一个值为ObjectId类型的”*id” 字段;如果MongoDB服务在新增Document的时候发现Document中没有”*id”字段,那么mongod会新增一个值为ObjectId类型的”*id”字段到该Document中。

MongoDB对单个Document的写操作是原子的。

MongoDB提供了如下的方式来进行新增操作:

  • db.collection.insert()
  • db.collection.insertOne() 3.2版本新增
  • db.collection.insertMany() 3.2版本新增

db.collection.insert()

insert操作可以新增单个Document,也可以新增多个Document。如果新增单个Document,则把需要新增的Document作为参数传递给insert(),如果新增多个Document,则将多个Document的数组作为参数传递个insert()函数。

比如我们需要在”post”这个collection上新增一个Document来表示我们的博客中新增了一篇文章,我们可以这么做:

img

现在,我们给post这个Collection新增了一个Document,表示在Blog中新增了一篇文章。我们可以看下现在post这个Collection中是不是有我们新增的Document。

img

这里我们使用findOne()来查询,我们可以看到,我们由于没有在Document中包含”*id”字段,所以MongoDB自动为我们新增了一个”*id”字段。

insert()函数可以一次新增多个Document,只要将一个Document的数组传递给insert()就可以了,如:

img

db.collection.insertOne()

insertOne()函数是在3.2版本中新增的,它用来添加单个Document。例子如下:

img

db.collection.insertMany()

insertMany()函数是insert的批量增加的版本,支持一次新增多个Document,它也是3.2版本中新增的函数:

img

好了,我们简单介绍了下insert操作的三个函数,下面,我们已经在MongoDB的数据库里新增了几个Document了。接下来,是时候开始学习查找操作来查看这些已经存储在MongoDB的记录了。

QUERY操作

MongoDB提供了db.collection.find()函数来执行查询操作,函数将返回一个游标(cursor),用于遍历查询到的Documents。find()函数接受两个参数,一个是过滤条件,还有一个是投影。

db.collection.find(  )
  • 用于查找满足过滤条件的Document
  • (投影)用于指定被找到的Document中需要返回哪些字段,用于限制网络中传输的数据的大小。投影的概念和关系数据库中的投影的概念基本是一致的。

现在,我们可以查询下刚才我们新增的所有的Documents,通过find(),我们来看下如何查询:

img

如果我们没有传递任何参数,或者传递一个”{}”给find()函数,那会find()返回Collection中所有的Document。现在,可以看到我们刚才新增的所有的Documents。

接下来,我们通过指定条件,查询标题为”Third Post”的Document,我们可以这样做:

img

发现了么,我们的查询条件其实就是以Document方式构造的。在MongoDB中,我们可以通过构造不同的Document来定义不同的查询条件。

除了使用具体的字段来过滤,我们还可以使用查询操作符来做更加灵活的操作。我们现在需要查找出标题是”Third Post”或”Fifth Post”这两篇Post中的任何一篇,我们可以使用**$in**操作符来查询:

img

除了使用**,还提供了很多有用的操作符来帮助构造过滤条件,如lt**, and, $or等。

使用子Document中值作为过滤条件

现在,我们假设有一篇文章,在Document中的存储如下:

img

现在,我们需要匹配内部Document中的条件,比如我们需要查找author中name是Duke的记录,我们可以这样构造我们的筛选条件:

db.post.findOne(
{
"author":
{
"name""Duke",
"email""740313507@qq.com"
}
})

查询结果就是这样的

img

我们观察这个过滤条件,发现和上面的过滤条件的结构一样,就是{“field”:”value”}的格式,只是不同的是,这次的”value”不再是一个普通的值了,而是一个Document。通过这种方式来过滤,具有一些局限性,我们如果要查找author中name是Duke的记录,我们必须完整指定author的值,也就是需要完整的Document。如果需要只过滤name,而不关系email的值,我们可以这样构造过滤条件:

db.post.findOne({"author.name""Duke"})

查询到和上面一样的结果

img

但是,这次我们使用了”author.name”的方式来指定field。这种类似于成员引用的”点符号”结构的查询,可以用来对内嵌的Document中的指定的field进行过滤。后面你将会看到,对于数组类型的值,也可以通过类似的方式来构造过滤条件。

使用数组中的元素作为过滤条件

接下来我们看下如何使用数组中的值来构造过滤条件。最简单的,也是最容易想到的,就是把整个数组作为过滤条件,类似于上面的把整个子Document作为过滤条件一样,我们可以这样构造

db.post.findOne({"comments": ["comment one""comment two"]})

查询的结果如下:

img
但是,这种方式没法指定数组中的某个值作为过滤件。如果要使用数组中的某个值作为过滤条件,我们可以这么构造过滤条件:
db.post.find({"comments""comment two"})

查询到的结果如下:

img

这里最后使用了”pretty()”方法来格式化输出,输出格式化的数据,便于观察,仅此而已,没有别的用途。我们可以看到,这种方式构造的过滤条件,使用了数组中的一个元素来筛选记录,只要数组中包含了这个元素(不管这个元素的下标),那么就会过滤出这条记录,有点像集合中的in操作。这种方式可以匹配数组中的一个元素。

接下来,我们更近一步,我们需要匹配数组的某一个下标位置的元素,那么我们需要使用上面一开始提到的,使用类似匹配子Document的那种成员引用(点符号)方式来构造过滤条件:

db.post.find({"comments.0""comment two"})

查询到的结果如下:

img

这里,我们使用{“comments.0”: “comment two”}的方式指定匹配的条件是:数组”comments”下标为0的位置的值为”comment two”。这样,就可以过滤掉之前下标为1的位置为”comment two”的记录了。可以看出,在使用数组下标构造过滤条件的时候,下标是从0开始的。

MongoDB提供了丰富的操作符来支持构造灵活的过滤条件,这里就先介绍这么点。由于篇幅关系,这里就不再展开了,下次独立写篇文章重点介绍下MongoDB中的查询操作。接下来,我们该看下如何在MongoDB中进行更新操作。

UPDATE操作

MongoDB也支持基本的更新操作,它提供了4个用于更新的方法:

  • db.collection.updateOne() 3.2版本新增
  • db.collection.updateMany() 3.2版本新增
  • db.collection.update()
  • db.collection.replaceOne() 3.2版本新增

这些Update方法支持三个参数:

  • 用于筛选记录的过滤条件,过滤出需要被更新的记录,过滤条件和query中使用的过滤条件类似。
  • 一个新的Document,用于更新部分值或者替换除了”_id”之外的一整个Document。
  • 一个以Document格式组织的一组更新选项。

MongoDB对于单个Document的更新操作是原子的。 MongoDB在更新时对于”*id”主键的处理原则是,不管是更新还是替换Document,都不能更改被更新的Document的”*id”主键,如果在替换的时候包含了不同的”_id”,那么替换会失败,如:

img

上面的例子中,我们修改了原先的”*id”值为1,然后进行替换更新,发现更新失败,提示”*id”值不能被更改。

当我们更新的时候,新的Document的大小超过了原先旧的Document的大小的时候,更新操作会重新申请一块更大的空间来存放这个新的Document。

接下来,我们来看下这些更新API的用法。

db.collection.updateOne()

updateOne()函数是在3.2版本中新增的一个API,用于更新一条匹配到的Document。现在我们需要更新我们的Post集合中的标题为”First Post”的Document,我们想增加一些评论,我们可以这么构造我们的更新表达式:

db.post.updateOne({"title""First Post"}, {"$set": {"comments": ["comment one"]}})
img

现在,我们的”First Post”这篇文章就有了一条评论了。这里我们使用”$set”操作符来设置一个新的字段,MongoDB的更新操作提供了一些有用的操作符来帮助构造更新语句。updateOne()函数会更新第一个被匹配到的Document。如果要更新多个Document,我们可以用updateMany()函数来支持。

db.collection.updateMany()

updateMany()函数可以对匹配到的所有的Document进行更新操作。比如我们想更新所有的文章,让每篇文章都有一个浏览数的字段,表示别浏览的次数。我们可以这样做:

db.post.updateMany({}, {"$set": {"view": 0}})
img

我们可以看到,通过updateMany()函数,我们更新了所有的Document,使得每个Document都包含了一个”view”字段,初始值为0。

替换Document

上面提到了两个API,都是对Document中的某个字段进行更新。它们除了可以对Document中的单个字段进行更新外,还可以对匹配到的整个Document进行替换(除了”*id”属性外,可以替换任何属性)。只要把更新参数改成一个普通的Document(Document的结构中不包含操作符),就可以对匹配到的Document替换成参数中的Document。进行Document替换更新的时候,需要注意:原先的Document中的”*id”属性是不能被更改的,所以新的用于替换的Document不能包含”*id”属性,如果包含了”*id”属性,那么这个”*id”属性必须是和被更新的Document的”*id”属性是相同的。

除了上面的两个API可以用于替换Document,MongoDB在3.2版本中新增了一个replaceOne()函数来进行替换操作。现在我们用replaceOne()来替换一个Document,我们把”title”是”First Post”的Document替换成新的Document:

db.post.replaceOne({"title""First Post"}, {"title""New Post""content""new content""create_time": new Date()})
img

现在,我们已经把”title”为”First Post”的Document替换为了新的”title”为”New Post”的Document了。

最后,我们来看下上面三个API的集大成者,就是update()函数,它基本包含了上面提到的三个API的所有功能,默认情况下,update()函数会更新匹配到的第一个Document,如果设置了”multi”选项,那么就可以更新匹配到的所有的Document。

下面我们使用update()来更新匹配到的第一个Document:

db.post.update({"title""New Post"}, {"$set": {"view": 0}})
img

好了,更新操作介绍到这里,接下来就是最后一个删除操作了。

DELETE操作

到这里,我想大家都已经了解了MongoDB中的”增”,”改”,”查”的功能了,接下来我们来看下”删”这个功能。MongoDB提供了三个用于删除操作的API,分别是:

  • db.collection.deleteOne()
  • db.collection.deleteMany() 3.2版本新增
  • db.collection.remove() 3.2版本新增

这三个API都支持一个过滤条件参数,用于匹配到满足条件的Document,然后进行删除操作。

从三个API的字面意思我们可以看出,deleteOne()会删除匹配到的所有的Document中的第一个,而deleteMany()和remove()会删除所有匹配到的Document。

假设我们需要删除”title”为”New Post”的Document,我们可以用deleteOne()来操作

db.post.deleteOne({"title""New Post"})
img

当删除了”title”为”New Post”的Document以后,我们再次去查询的时候,发现这个Document确实已经被删除了。deleteOne()用于删除单个Document,如果我们需要删除所有满足过滤条件的Document的话,我们可以用deleteMany()或者remove()来实现。

现在我们想删除所有浏览数为0的文章,那么我们可以用deleteMany()或者remove来实现:

db.post.remove({"view": 0})
img

由于我们存储在集合中的所有Document的view值都是0,所以上面的操作相当于我们清空了我们的Collection。

以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !

img
本文由 良许Linux教程网 发布,可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。
良许

作者: 良许

良许,世界500强企业Linux开发工程师,公众号【良许Linux】的作者,全网拥有超30W粉丝。个人标签:创业者,CSDN学院讲师,副业达人,流量玩家,摄影爱好者。
上一篇
下一篇

发表评论

邮箱地址不会被公开。 必填项已用*标注

联系我们

联系我们

公众号:良许Linux

在线咨询: QQ交谈

邮箱: yychuyu@163.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部