详解MongoDB中的CRUD操作

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

MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型,本篇文章重点为大家讲解一下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来表示我们的博客中新增了一篇文章,我们可以这么做:

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

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

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

db.collection.insertOne()

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

db.collection.insertMany()

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

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

QUERY操作

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

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

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

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

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

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

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

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

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

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

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

db.post.findOne(
{
"author":
{
"name""Duke",
"email""[email protected]"
}
})

查询结果就是这样的

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

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

查询到和上面一样的结果

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

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

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

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

查询的结果如下:

但是,这种方式没法指定数组中的某个值作为过滤件。如果要使用数组中的某个值作为过滤条件,我们可以这么构造过滤条件:

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

查询到的结果如下:

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

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

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

查询到的结果如下:

这里,我们使用{“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”,那么替换会失败,如:

上面的例子中,我们修改了原先的”*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"]}})

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

db.collection.updateMany()

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

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

我们可以看到,通过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()})

现在,我们已经把”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}})

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

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"})

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

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

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

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

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/222813.html<

(0)
运维的头像运维
上一篇2025-04-15 16:21
下一篇 2025-04-15 16:23

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

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