MongoDB:14-MongoDB- 原子操作

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介: MongoDB:14-MongoDB- 原子操作


  1. Redis采用的是异步I/O非阻塞的单进程模型,每一条Redis命令都是原子性的。
  2. 那么mongoDB呢? mongo有哪些原子操作呢?有哪些实现事务性操作的技巧呢?


MongoDB 原子操作


  1. mongodb不支持事务,所以,在你的项目中应用时,要注意这点。无论什么设计,都不要要求mongodb保证数据的完整性。
  2. 但是mongodb提供了许多原子操作,比如文档的保存,修改,删除等,都是原子操作。
  3. 所谓原子操作就是要么这个文档保存到Mongodb,要么没有保存到Mongodb,不会出现查询到的文档没有保存完整的情况。




原子操作数据模型


  • 考虑下面的例子,图书馆的书籍及结账信息。
  • 实例说明了在一个相同的文档中如何确保嵌入字段关联原子操作(update:更新)的字段是同步的


  1. book = {
  2.          _id: 123456789,
  3.          title: "MongoDB: The Definitive Guide",
  4.          author: [ "Kristina Chodorow", "Mike Dirolf" ],
  5.          published_date: ISODate("2010-09-24"),
  6.          pages: 216,
  7.          language: "English",
  8.          publisher_id: "oreilly",
  9.          available: 3,
  10.          checkout: [ { by: "joe", date: ISODate("2012-10-15") } ]
  11.        }


  • 你可以使用 db.collection.findAndModify() 方法来判断书籍是否可结算并更新新的结算信息
  • 在同一个文档中嵌入的 available 和 checkout 字段来确保这些字段是同步更新的:



  1. db.books.findAndModify ( {
  2.   query: {
  3.            _id: 123456789,
  4.            available: { $gt: 0 }
  5.          },
  6.   update: {
  7.             $inc: { available: -1 },
  8.             $push: { checkout: { by: "abc", date: newDate() } }
  9.           }
  10. } )
  11. 拥有类似事务特性的更新与查询操作——findAndModify.

  12. 它是原子性的,会返回符合查询条件的更新后的文档。

  1. db.COLLECTION_NAME.findAndModify({query:{},
  2.                                 update:{},
  3.                                 remove:true|false,
  4.                                 new:true|false,
  5.                                 sort:{},
  6.                                 fields:{},
  7.                                 upsert:true|false});
  • query是查询选择器,与findOne的查询选择器相同
  • update是要更新的值,不能与remove同时出现
  • remove表示删除符合query条件的文档,不能与update同时出现
  • newtrue:返回个性后的文档,false:返回个性前的,默认是false
  • sort:排序条件,与sort函数的参数一致。
  • fields:投影操作,与find*的第二个参数一致。
  • upsert:与updateupsert参数一样。
  1. 不论是update的第二个参数,还是findAndModify的update,在不指定更新操作符的情况下,将会用指定的新值替换旧值。
  2. 比如,
  1. use iteye;
  2. db.blog.update({_id:ObjectId('......')},{title:'new title'});

  1. //上面的操作就把指定_id的文档的标题改成了‘new title’
  • 如果指定了更新操作符,就可以实现更复杂灵活的更新操作。
  • 可以通过更新操作符,增加或减少数值,针对数组类型的属性,做类似队列或栈的操作。
  • 单从这一点来说,mongo要比sql数据库强大的多了。




原子操作常用命令(更新操作符)


  • $set
  • 用来指定一个键并更新键值,若键不存在并创建。


  1.  用"$set"甚至可以修改键的数据类型
  1. db.users.insert({"name":"egger", "age": 28, "sex" : "male"})
  2. db.users.update({"_id" : ObjectId("51826852c75fdd1d8b805801")},{"$set" : {"sex" :1 }} )

  1. { $set : { field : value } }
  1. 使用"$set"修改内嵌文档:
  2. db.posts.update({"author.name":"egger"},{"$set":{"author.name":"mongo","author.age":18}})


  • $unset
  • 用来删除一个键。
  1. { $unset : { field : 1} }


  • $inc
  • $inc可以对文档的某个值为数字型(只能为满足要求的数字)的键进行增减的操作。
  1. 负数,表示减少
  2. "$inc"只能用于整数、长整数或双精度浮点数。要是用在其他类型的数据上就会导致操作失败。
  3. { $inc : { field : value } }
  • upsert
  1. upsert是一种特殊的更新操作,不是一个操作符。(upsert = up[date]+[in]sert)
  2. update() 方法的三个参数是upsert,这个参数是个布尔类型,默认是false
  3. 当它为true的时候,update方法会首先查找与第一个参数匹配的记录,在用第二个参数更新之,
  4. 如果找不到与第一个参数匹配的的记录,
  5. 就会以这个条件和更新文档为基础创建一个新的文档。如果找到了匹配的文档,则正常更新。
  6. upsert非常方便,不必预置集合,同一方法可以既创建又更新文档。

  • $setOnInsert
  1. 当update方法使用upsert选项执行insert操作时,$setOnInsert操作符给相应的字段赋值。类似sql中update 语句的set。
  1. db.collection.update( <query>,
  2.                      { $setOnInsert: { <field1>: <value1>, ... } },
  3.                      { upsert: true }   //{ upsert: true }可以用true替换
  4.                    )


  • $(query)
  1. $ (query)
  1. 语法: { "<array>.$" : value }
  2.  当对数组字段进行更新时,且没有明确指定的元素在数组中的位置,
  3.  我们使用定位操作符("$")标识一个元素,数字都是以0开始的。
  4.   
  5. 和update()一起使用:

  1. 定位操作符("$")作为第一个匹配查询条件的元素的占位符,也就是在数组中的索引值。
  2. 数组字段必须出现查询文档中。
  3.   集合students中有两条文档:
  1. { "_id" : 1, "grades" : [ 78, 88, 88 ] }
  2. { "_id" : 2, "grades" : [ 88, 90, 92 ] }
  1.   执行下列语句创建集合文档数据:
  1. db.students.remove();
  2. db.students.insert({ "_id" : 1, "grades" : [ 78, 88, 88 ] });
  3. db.students.insert({ "_id" : 2, "grades" : [ 88, 90, 92 ] });

  1.   执行下列操作:
  2. //查询匹配的文档中,数组有2个88,只更新第一个匹配的元素,也就是"grades.1"
  1. db.students.update( { _id: 1, grades: 88 }, { $set: { "grades.$" : 82 } }) ;

  1. //查询文档中没有出现grades字段,查询报错
  1. db.students.update( { _id: 2 }, { $set: { "grades.$" : 82 } } );


  • $push
  • 用法:
  1. { $push : { field : value } }
  1. 把value追加到field里面去,field一定要是数组类型才行,如果field不存在,会新增一个数组类型加进去。
  • $pushAll
  • 同$push,只是一次可以追加多个值到一个数组字段内。
  1. { $pushAll : { field : value_array } }

  • $pull
  • 从数组field内删除一个等于value值。
  1. 语法:db.collection.update( { field: <query> }, { $pull: { field: <query> } } );
  2. { $pull : { field : _value } }
  3. //插入一条文档
  4. db.profiles.insert({ votes: [ 3, 5, 6, 7, 7, 8 ] });
  5. //移除数组中所有元素7
  6. db.profiles.update( { votes: 3 }, { $pull: { votes: 7 } } );
  7. //移除数组中所有大于6的元素
  8. db.profiles.update( { votes: 3 }, { $pull: { votes: { $gt: 6 } } } );
  9. //Result
  10. { votes: [ 3, 5, 6, 8 ] }
  11. { votes: [ 3, 5, 6 ] }



  • $addToSet


  • 增加一个值到数组内,而且只有当这个值不在数组内才增加。


  • $pop
  • 删除数组的第一个或最后一个元素
  1. { $pop : { field : 1 } }



  • $rename
  • 修改字段名称
  1. $rename操作符可以重命名字段名称,新的字段名称不能和文档中现有的字段名相同。
  2. 如果文档中存在A、B字段,将B字段重命名为A,$rename会将A字段和值移除掉,然后将B字段名改为A.
  3.  当重命名子文档字段名时需要使用"."操作符,格式:值为该子文档的字段名.子文档中字段名。
  1. $rename操作符也可以将子文档中键值移到其他子文档中。
  1. db.students.update( { _id: 1 }, { $rename: { "name.last": "contact.lname" } } )
  1. 我们将名为name的子文档中的last字段,重名为“lname”,同时将其移动到子文档contact中,
  2. 若contact字段不存在,数据库会新建该字段。

  1. { $rename : { old_field_name : new_field_name } }
  2. 若指定的字段在集合中不存在,$rename操作符将不会有任何影响。
  1. db.students.update( { _id: 1 }, { $rename: { 'wife': 'spouse' } } )
  2.   若指定的多个字段在集合中都不存在,$rename操作符将不会有任何影响。
  3. db.students.update( { _id: 1 }, { $rename: { 'wife': 'spouse', 'vice': 'vp',  'office': 'term' } } )
  4.   集合中不存在上面语句中指定的wife、vice、office字段,所以上述的更新操作无任何影响。

  1. 若指定的多个字段中,有的在集合中存在,有的不存在,$rename操作符执行下列操作:
  1. 存在的字段按照上面的规则重命名为新的名称。
  2. 不存在的字段对数据无任何影响。



  • $bit
  • 位操作,integer类型
  1. {$bit : { field : {and : 5}}}


  • 偏移操作符
  1. > t.find() { "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC", "comments" : [ { "by" : "joe", "votes" : 3 }, { "by" : "jane", "votes" : 7 } ] }
  2. > t.update( {'comments.by':'joe'}, {$inc:{'comments.$.votes':1}}, false, true )
  3. > t.find() { "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC", "comments" : [ { "by" : "joe", "votes" : 4 }, { "by" : "jane", "votes" : 7 } ] }
  4. update() 方法
  5. update() 方法用于更新已存在的文档。语法格式如下:
  1. db.collection.update(
  2.   <query>,
  3.   <update>,
  4.   {
  5.     upsert: <boolean>,
  6.     multi: <boolean>,
  7.     writeConcern: <document>
  8.   }
  9. )

  1. 参数说明:
  1. query : update的查询条件,类似sql update查询内where后面的。
  2. update : update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的
  3. upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
  4. multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
  5. writeConcern :可选,抛出异常的级别。

参考来源: http://www.runoob.com/mongodb/mongodb-atomic-operations.html


相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
目录
相关文章
|
3月前
|
NoSQL MongoDB
MongoDB 原子操作
10月更文挑战第21天
40 2
|
7月前
|
监控 NoSQL 安全
MongoDB 原子操作:确保数据一致性和完整性的关键
MongoDB 原子操作:确保数据一致性和完整性的关键
103 0
|
NoSQL MongoDB
开心档-软件开发入门之MongoDB 原子操作
【摘要】 本章将会讲解mongodb不支持事务,所以,在你的项目中应用时,要注意这点。无论什么设计,都不要要求mongodb保证数据的完整性。
|
NoSQL MongoDB
​​​软件开发入门教程网之​​MongoDB 原子操作
本章将会讲解mongodb不支持事务,所以,在你的项目中应用时,要注意这点。无论什么设计,都不要要求mongodb保证数据的完整性。
​​​软件开发入门教程网之​​MongoDB 原子操作
|
3月前
|
存储 关系型数据库 MySQL
一个项目用5款数据库?MySQL、PostgreSQL、ClickHouse、MongoDB区别,适用场景
一个项目用5款数据库?MySQL、PostgreSQL、ClickHouse、MongoDB——特点、性能、扩展性、安全性、适用场景比较
|
4月前
|
存储 NoSQL 关系型数据库
非关系型数据库-MongoDB技术(二)
非关系型数据库-MongoDB技术(二)
|
22天前
|
存储 JSON NoSQL
学习 MongoDB:打开强大的数据库技术大门
MongoDB 是一个基于分布式文件存储的文档数据库,由 C++ 编写,旨在为 Web 应用提供可扩展的高性能数据存储解决方案。它与 MySQL 类似,但使用文档结构而非表结构。核心概念包括:数据库(Database)、集合(Collection)、文档(Document)和字段(Field)。MongoDB 使用 BSON 格式存储数据,支持多种数据类型,如字符串、整数、数组等,并通过二进制编码实现高效存储和传输。BSON 文档结构类似 JSON,但更紧凑,适合网络传输。
60 15
|
30天前
|
存储 NoSQL 关系型数据库
阿里云数据库MongoDB版助力信也科技 打造互联网金融企业样板
我们的风控系统引入阿里云数据库MongoDB版后,解决了特征类字段灵活加减的问题,大大提高了开发效率,极大的提升了业务用户体验,获得了非常好的效果
阿里云数据库MongoDB版助力信也科技 打造互联网金融企业样板
|
2月前
|
NoSQL Cloud Native atlas
探索云原生数据库:MongoDB Atlas 的实践与思考
【10月更文挑战第21天】本文探讨了MongoDB Atlas的核心特性、实践应用及对云原生数据库未来的思考。MongoDB Atlas作为MongoDB的云原生版本,提供全球分布式、完全托管、弹性伸缩和安全合规等优势,支持快速部署、数据全球化、自动化运维和灵活定价。文章还讨论了云原生数据库的未来趋势,如架构灵活性、智能化运维和混合云支持,并分享了实施MongoDB Atlas的最佳实践。
|
3月前
|
NoSQL Cloud Native atlas
探索云原生数据库:MongoDB Atlas 的实践与思考
【10月更文挑战第20天】本文探讨了MongoDB Atlas的核心特性、实践应用及对未来云原生数据库的思考。MongoDB Atlas作为云原生数据库服务,具备全球分布、完全托管、弹性伸缩和安全合规等优势,支持快速部署、数据全球化、自动化运维和灵活定价。文章还讨论了实施MongoDB Atlas的最佳实践和职业心得,展望了云原生数据库的发展趋势。