MongoDB的CRUD操作

1. 前言

在上一篇文章中,我们介绍了MongoDB。现在,我们来看下如何在MongoDB中进行常规的CRUD操作。毕竟,作为一个存储系统,它的基本功能就是对数据进行增删改查操作。

MongoDB中的增删改查操作,不同于我们熟悉的关系数据库中的操作。在关系数据库中,比如MySQL,我们通常使用SQL语句对数据库进行增(INSERT)删(DELETE)改(UPDATE)查(SELECT)。MongoDB在对数据进行操作过程中,使用的是Document进行数据操作。在对数据库进行操作的时候,使用Document来表示需要查询的条件和需要更新的数据,功能类似于关系数据库中的SQL语句。接下来,我们来看下在MongoDB中是如何通过Document来进行CRUD操作的。

注意:下面介绍的CRUD操作,是在MongoDB的mongo shell操作的。mongo shell是一个JavaScript交互环境,是MongoDB提供的一个客户端。不同的语言有自己对应的驱动和对应的操作API,但是原理是类似的。相信通过在mongo shell中进行CRUD操作的介绍,大家也可以举一反三,在不同的语言中操作MongoDB。

2. 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版本新增

2.1 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()就可以了,如:

2.2 db.collection.insertOne()

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

2.3 db.collection.insertMany()

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

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

3. QUERY操作

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

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

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

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

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

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

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

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

3.1 使用子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进行过滤。后面你将会看到,对于数组类型的值,也可以通过类似的方式来构造过滤条件。

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

接下来我们看下如何使用数组中的值来构造过滤条件。最简单的,也是最容易想到的,就是把整个数组作为过滤条件,类似于上面的把整个子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中进行更新操作。

4. 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的用法。

4.1 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()函数来支持。

4.2 db.collection.updateMany()

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

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

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

4.3 替换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}})

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

5. 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。

6. 总结

好了,到这里,我们已经简单介绍了MongoDB中相关的CRUD操作了。相信大家对MongoDB的基本操作有了一些简单的认识了。

差不多就先写到这里了,由于文章的主题就是跟大家介绍MongoDB的CRUD操作,所以上面很多的细节部分没有展开,感兴趣的同学可以去翻阅MongoDB的文档来了解,有机会,下次单独拎出来好好总结下。毕竟,我们学东西,得先有个大概的了解以后,才可以有针对的深入,一味的追求细节,往往会迷失方向。

时间: 2024-08-05 11:16:16

MongoDB的CRUD操作的相关文章

Ruby操作MongoDB(进阶)-CRUD操作

MongDB数据库的使用离不开CRUD操作.什么是CRUD,就是创建文档,读取文档信息,更新文档和删除文档. key-value键值对标记 在MongoDB的Ruby驱动中,Key_value键值多次出现.而且有时会出现语法上的巧合,这取决于在使用的Ruby版本中如何申明. 在文档创建步骤中,1.9及之后版本支持以下语法: document={name:"Tom",age:20}. 但是如果你使用的是2.2或者更高的版本,你可以用双引号将你的key包起来.如: document={&q

【翻译】MongoDB指南/CRUD操作(三)

[原文地址]https://docs.mongodb.com/manual/ CRUD操作(三) 主要内容: 原子性和事务(Atomicity and Transactions),读隔离.一致性和新近性,分布式查询(Distributed Queries),分布式写操作,模拟两阶段任务提交,在副本集中执行配额读取 1 原子性和事务(Atomicity and Transactions) 在MongoDB中,写操作在单文档级别具有原子性,即使修改一个文档中的多个嵌入式文档也是如此. 当一个写操作修

MongoDB对图片进行CRUD操作——与JAVA结合

上几篇博客简单对MongoDB进行了简单介绍和如何安装,以及在dos下是如何操作MongoDB和在安装MongoDB中,出现了什么错误,是如何解决的.当然这些都还不够,我们还要用到实际当中去.我用MyEclipse+JDK1.7做了一个简单的demo,来展示下MongoDB怎么运用到实际中去. MongoDB作为一个NoSql数据库的代表,存取多媒体数据,应该是强项吧?那么,在MongoDB中是如何对图片进行CRUD操作的. 上几篇博客中已经提到,MongoDB的文档结构是BSON格式,BSON

【翻译】MongoDB指南/CRUD操作(二)

[原文地址]https://docs.mongodb.com/manual/ MongoDB CRUD操作(二) 主要内容: 更新文档,删除文档,批量写操作,SQL与MongoDB映射图,读隔离(读关注),写确认(写关注) 1 更新文档 1.1 更新 MongoDB提供下列方法用于更新一个集合 db.collection.updateOne() 更新使用指定过滤器匹配到的文档,即使过滤器匹配到多个文档,也只会更新一个文档. 3.2版本新增特性. db.collection.updateMany(

【翻译】MongoDB指南/CRUD操作(一)

[原文地址]https://docs.mongodb.com/manual/ MongoDB CRUD操作(一) 主要内容:CRUD操作简介,插入文档,查询文档. CRUD操作包括创建.读取.更新和删除文档. 创建操作 执行创建或者插入操作可向集合中添加文档.如果集合不存在,插入操作会创建此集合. MongoDB提供下列方法向集合中插入文档: db.collection.insert() db.collection.insertOne()  3.2版本新增 db.collection.inser

MongoDB的CRUD操作(java Util )

1.保存插入操作: public static synchronized String insert(DBObject record) { DBCollection col = MongoDB.getDBCollection(TABLE_NAME); record.put("time", new Date().getTime()); WriteResult result = col.insert(record); //当前插入表的_id return record.get("

mongodb的CRUD操作三

聚合操作 count()统计行数 计算总计 sum aggregate是聚合的操作符,然后分组,然后再sum

mongodb的CRUD操作二查询

---恢复内容开始--- 查询才是我们用的最多最多的 find() 查询所有的行 指定一个关键字的查询 那么我想看这个列的所有行 前面的{}是代表了我没有加任何的条件 这里是代表是我要找uname是LY的行的deptnolie.前面的_id:0是代表我不想显示_id这个列 这里就是代表了我想要看这些列的所有行可以对比一下 过滤一些列的写法xxx:0就可以了 去重 distinct("列名") 这样我就可以把这列的值去重了 分页查询 加了条件的限制查询 跳开前几行: 从第3行开始到第6行

Mongodb的安装与CRUD操作

What is Mongodb ?         Mongo DB是一款开源的非关系型数据库(NoSql)其文档模型自由灵活,可以让你在开发过程中畅顺无比.对于大数据量.高并发.弱事务的互联网应用,MongoDB可以应对自如.MongoDB内置的水平扩展机制提供了从百万到十亿级别的数据量处理能力,完全可以满足Web2.0和移动互联网的数据存储需求,其开箱即用的特性也大大降低了中小型网站的运维成本. 安装Mongodb 来到mongodb官网http://www.mongodb.org/可以在这