$slice

如果希望数组的最大长度是固定的,那么可以将 $slice 和 $push 组合在一起使用,就可以保证数组不会超出设定好的最大长度。$slice 的值必须是负整数。

假设$slice的值为10,如果$push 后的数组的元素个数小于10,那么所有元素都会保留。反之,只有最后那10个元素会保留。因此,$slice 可以用来在文档中创建一个队列。

  1. db.class.insert({"班级":"1班"})
  2.  
  3. WriteResult({ "nInserted" : })
  4. > db.class.update(
  5. ... {"班级":"1班"},
  6. ... {"$push":{"students":{
  7. ... "$each":["zs","ls","ww"],
  8. ... "$slice":-}}})
  9. WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
  10. > db.class.findOne()
  11. {
  12. "_id" : ObjectId("5854b5a0e7d717fcb974637b"),
  13. "班级" : "1班",
  14. "students" : [
  15. "zs",
  16. "ls",
  17. "ww"
  18. ]
  19. }
  20.  
  21. > db.class.update(
  22. ... {"班级":"1班"},
  23. ... {"$push":{"students":{
  24. ... "$each":["yyb","rhr","www","qqq","eee","rrr"],
  25. ... "$slice":-}}})
  26. WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
  27. > db.class.findOne()
  28. {
  29. "_id" : ObjectId("5854b5a0e7d717fcb974637b"),
  30. "班级" : "1班",
  31. "students" : [
  32. "rhr",
  33. "www",
  34. "qqq",
  35. "eee",
  36. "rrr"
  37. ]
  38. }
  39. >

也可以在清理元素之前使用$sort,只要向数组中添加子对象就需清理,先排序后保留指定的个数。

  1. > db.class.update({},{ "班级" : "一班"})
  2. WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
  3. > db.class.update(
  4. ... {"班级":"一班"},
  5. ... {"$push":{"students":
  6. ... {"$each":[{"name":"aaa","age":},{"name":"bbb","age":},{"name":"ccc","age":}],
  7. ... "$slice":-,
  8. ... "$sort":{"age":-}}}})
  9. WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
  10. > db.class.findOne()
  11. {
  12. "_id" : ObjectId("5854b5a0e7d717fcb974637b"),
  13. "班级" : "一班",
  14. "students" : [
  15. {
  16. "name" : "bbb",
  17. "age" :
  18. },
  19. {
  20. "name" : "aaa",
  21. "age" :
  22. }
  23. ]
  24. }
  25. >

$ne与$addToSet

如果想将数组作为数据集使用,保证数组内的元素不会重复。可以在查询文档中用$ne或者$addToSet来实现。有些情况$ne根本行不通,有些时候更适合用$addToSet。

  1. > db.papers.insert({"authors cited":["yyb"]})
  2. WriteResult({ "nInserted" : })
  3. > db.papers.update({"authors cited":{"$ne":"Richie"}}, {"$push":{"authors cited":"Richie"}})
  4. WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
  5. > db.papers.findOne()
  6. {
  7. "_id" : ObjectId("5854c900e7d717fcb974637e"),
  8. "authors cited" : [
  9. "yyb",
  10. "Richie"
  11. ]
  12. }
  13. > db.papers.update({"authors cited":{"$ne":"Richie"}}, {"$push":{"authors cited":"Richie"}})
  14. WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
  15. >
  1. db.user.findOne()
  2. {
  3. "_id" : ObjectId("5854cb40e7d717fcb974637f"),
  4. "username" : "joe",
  5. "emails" : [
  6. "joe@example.com",
  7. "joe@gmail.com",
  8. "joe@yahoo.com"
  9. ]
  10. }
  11.  
  12. > db.user.update(
  13. ... ... {"username":"joe"},
  14. ... ... {"$addToSet":{"emails":"joe@gmail.com"}})
  15. WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
  16. > db.user.update(
  17. ... ... ... {"username":"joe"},
  18. ... ... ... {"$addToSet":{"emails":"joe@hotmail.com"}})
  19. WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
  20. > db.user.findOne()
  21. {
  22. "_id" : ObjectId("5854cb40e7d717fcb974637f"),
  23. "username" : "joe",
  24. "emails" : [
  25. "joe@example.com",
  26. "joe@gmail.com",
  27. "joe@yahoo.com",
  28. "joe@hotmail.com"
  29. ]
  30. }
  31. >

将$addToSet和$each组合起来,可以添加多个不同的值。而用$ne和$push组合就不能实现。

$addToSet与$push的区别:前者添加到数组中时会去重,后者不会。

  1. >db.user.insert({ "username" : "joe"})
  2. > db.user.update(
  3. ... {"username" : "joe"},
  4. ...
  5. ... {"$addToSet":
  6. ... {"emails" :{"$each": [
  7. ... "joe@example.com",
  8. ... "joe@gmail.com",
  9. ... "joe@yahoo.com",
  10. ... "joe@hotmail.com",
  11. ... "joe@hotmail.com"]}}})
  12. WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
  13. > db.user.findOne()
  14. {
  15. "_id" : ObjectId("5854ce5ce7d717fcb9746380"),
  16. "username" : "joe",
  17. "emails" : [
  18. "joe@example.com",
  19. "joe@gmail.com",
  20. "joe@yahoo.com",
  21. "joe@hotmail.com"
  22. ]
  23. }
  24. >

从数组中删除元素

$pop

可以从数组任何一端删除元素。

{“$pop”:{“key”:1}}从数组末尾删除一个元素

{“$pop”:{“key”:-1}}从数组头部删除一个元素

  1. > db.class.findOne()
  2. {
  3. "_id" : ObjectId("5854b5a0e7d717fcb974637b"),
  4. "班级" : "一班",
  5. "students" : [
  6. {
  7. "name" : "bbb",
  8. "age" :
  9. },
  10. {
  11. "name" : "aaa",
  12. "age" :
  13. }
  14. ]
  15. }
  16. > db.class.update(
  17. ... {"班级" : "一班"},
  18. ... {"$pop":{"students":}})
  19. WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
  20. > db.class.findOne()
  21. {
  22. "_id" : ObjectId("5854b5a0e7d717fcb974637b"),
  23. "班级" : "一班",
  24. "students" : [
  25. {
  26. "name" : "bbb",
  27. "age" :
  28. }
  29. ]
  30. }
  31. >

$pull

有时需要基于特定条件来删除,而不仅仅是依据元素位置,这时可以使用$pull。$pull会将所有匹配的文档删除,而不是只删除一个。

  1. > db.list.insert(
  2. ... {"todo":["dishes","laundry","dry cleaning"]})
  3. WriteResult({ "nInserted" : })
  4. > db.list.update({},{"$pull":{"todo":"laundry"}})
  5. WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
  6. > db.list.findOne()
  7. {
  8. "_id" : ObjectId("585690afc5b0525a48a441b4"),
  9. "todo" : [
  10. "dishes",
  11. "dry cleaning"
  12. ]
  13. }
  14. >

数组操作符只能用于包含数组值的键。例如:不能将一个整数插入数组,也不能将一个字符串从数组中弹出。要修改标量值,使用$set或$inc。

基于位置的数组修改器

有两种方法操作数组中的值:通过位置或者定位操作符($)

位置

通过数组位置来操作。数组都是以0开头的,可以将下标直接作为键来选择元素。

  1. > db.blog.insert(
  2. ... {
  3. ... "content": "...",
  4. ... "comments": [
  5. ... {
  6. ... "comment": "good post",
  7. ... "author": "john",
  8. ... "votes":
  9. ... },
  10. ... {
  11. ... "comment": "i thought it was too short",
  12. ... "author": "claire",
  13. ... "votes":
  14. ... },
  15. ... {
  16. ... "comment": "free watches",
  17. ... "author": "alice",
  18. ... "votes": -
  19. ... }
  20. ... ]
  21. ... })
  22. WriteResult({ "nInserted" : })
  23.  
  24. > db.blog.update({"content":"..."},{"$inc":{"comments.0.votes":}})
  25. WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
  26. > db.blog.findOne()
  27. {
  28. "_id" : ObjectId("585694e4c5b0525a48a441b5"),
  29. "content" : "...",
  30. "comments" : [
  31. {
  32. "comment" : "good post",
  33. "author" : "john",
  34. "votes" :
  35. },
  36. {
  37. "comment" : "i thought it was too short",
  38. "author" : "claire",
  39. "votes" :
  40. },
  41. {
  42. "comment" : "free watches",
  43. "author" : "alice",
  44. "votes" : -
  45. }
  46. ]
  47. }
  48. >

定位操作符$

如果无法知道要修改的数组的下标,可以使用定位操作符$,用来定位查询文档已经匹配的元素,并进行更新。

  1. > db.blog.update(
  2. ... {"comments.author":"john"},
  3. ... {"$set":{"comments.$.author":"jim"}})
  4. WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
  5. > db.blog.findOne()
  6. {
  7. "_id" : ObjectId("585694e4c5b0525a48a441b5"),
  8. "content" : "...",
  9. "comments" : [
  10. {
  11. "comment" : "good post",
  12. "author" : "jim",
  13. "votes" :
  14. },
  15. {
  16. "comment" : "i thought it was too short",
  17. "author" : "claire",
  18. "votes" :
  19. },
  20. {
  21. "comment" : "free watches",
  22. "author" : "alice",
  23. "votes" : -
  24. }
  25. ]
  26. }
  27. >

upsert

upsert是update()的第三个参数。表示没有则创建,有则正常更新。

  1. > db.analytics.update({"url":"/blog"},{"$inc":{"pageviews":}},true)
  2. WriteResult({
  3. "nMatched" : ,
  4. "nUpserted" : ,
  5. "nModified" : ,
  6. "_id" : ObjectId("58569d3cb6687ca8dfad4e01")
  7. })
  8. > db.analytics.findOne()
  9. {
  10. "_id" : ObjectId("58569d3cb6687ca8dfad4e01"),
  11. "url" : "/blog",
  12. "pageviews" :
  13. }
  14. > db.analytics.update({"url":"/blog"},{"$inc":{"pageviews":}},true)
  15. WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
  16. > db.analytics.findOne()
  17. {
  18. "_id" : ObjectId("58569d3cb6687ca8dfad4e01"),
  19. "url" : "/blog",
  20. "pageviews" :
  21. }
  22. >

$setOnInsert

在创建文档的同时创建字段并为它赋值,但是在之后的所有更新操作中在,这个字段的值都不在改变。

$setOnInsert只会在文档插入时设置字段的值。

在预置或者初始化计数器时,或者对于不使用ObjectIds的集合来说,“$setOnInsert”是非常有用的。

  1. > db.user.update({},{"$setOnInsert":{"createAt":new Date()}},true)
  2. WriteResult({
  3. "nMatched" : ,
  4. "nUpserted" : ,
  5. "nModified" : ,
  6. "_id" : ObjectId("58569fe1b6687ca8dfad4e02")
  7. })
  8. > db.user.findOne()
  9. {
  10. "_id" : ObjectId("58569fe1b6687ca8dfad4e02"),
  11. "createAt" : ISODate("2016-12-18T14:40:33.273Z")
  12. }
  13. > db.user.update({},{"$setOnInsert":{"createAt":new Date()}},true)
  14. WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
  15. > db.user.findOne()
  16. {
  17. "_id" : ObjectId("58569fe1b6687ca8dfad4e02"),
  18. "createAt" : ISODate("2016-12-18T14:40:33.273Z")
  19. }
  20. >

save

一个shell函数,不存在创建,反之则更新文档。

它只有一个参数:文档。要是这个文档含有“_id”键,save会调用upsert。否则会调用insert。在shell中快速对文档进行修改。

  1. > db.user.save({"x":,"y":})
  2. WriteResult({ "nInserted" : })
  3. > var x=db.user.findOne()
  4. > x.num=
  5.  
  6. > db.user.save(x)
  7. WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
  8. > db.user.findOne()
  9. {
  10. "_id" : ObjectId("5856a230c5b0525a48a441be"),
  11. "x" : ,
  12. "y" : ,
  13. "num" :
  14. }

更新多个文档

默认情况下,只会更新匹配的第一个文档。要更新多个文档,需要将update的第4个参数设置为true。

想要知道多文档更新到底更新了多少文档,可以运行getLastError命令。键n的值就是被更新文档的数量。

  1. > db.coll.find()
  2. { "_id" : ObjectId("5856994bc5b0525a48a441b9"), "x" : "a" }
  3. { "_id" : ObjectId("58569966c5b0525a48a441ba"), "x" : "bbb" }
  4. { "_id" : ObjectId("5856996fc5b0525a48a441bb"), "x" : "c" }
  5. > db.coll.update({},{"$set":{"x":}},false,true )
  6. WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
  7. > db.runCommand({getLastError:})
  8. {
  9. "connectionId" : ,
  10. "updatedExisting" : true,
  11. "n" : ,
  12. "syncMillis" : ,
  13. "writtenTo" : null,
  14. "err" : null,
  15. "ok" :
  16. }
  17. >

返回被更新的文档

通过findAndModify命令得到被更新的文档。返回的是修改之前的文档。

对于操作队列以及执行其他需要进行原子性取值和赋值的操作非常方便。

  1. ps=db.runCommand({"findAndModify":"processes", "query":{"status":"ready"},
  2. "sort":{"pirority":-},
  3. "update":{"$set":{"status":"Running"}}})
  4. {
  5. "lastErrorObject" : {
  6. "updatedExisting" : true,
  7. "n" :
  8. },
  9. "value" : {
  10. "_id" : ObjectId("5857c939d7a32a888bd79c47"),
  11. "pirority" : ,
  12. "status" : "ready"
  13. },
  14. "ok" :
  15. }
  1. > db.processes.findOne("_id":ps.value._id)
  2. --19T19::04.904+ E QUERY [thread1] SyntaxError: missing ) after argument list @(shell)::
  3.  
  4. > db.processes.findOne({"_id":ps.value._id})
  5. {
  6. "_id" : ObjectId("5857c939d7a32a888bd79c47"),
  7. "pirority" : ,
  8. "status" : "Running"
  9. }
  10. >

findAndModify可以使用update键也可以使用remove键。Remove键表示将匹配的文档从集合里面删除。

  1. > ps=db.runCommand({"findAndModify":"processes", "query":{"status":"ready"},
  2. "sort":{"priority":-},
  3. "remove":true}).value
  4. {
  5. "_id" : ObjectId("5857c9b1d7a32a888bd79c48"),
  6. "pirority" : ,
  7. "status" : "ready"
  8. }
  9.  
  10. > db.processes.findOne({"_id":ps._id})
  11. null

MongoDB学习笔记四—增删改文档下的更多相关文章

  1. MongoDB学习笔记三—增删改文档上

    插入insert 单条插入 > db.foo.insert({"bar":"baz"}) WriteResult({ }) 批量插入 > db.fo ...

  2. MongoDB学习笔记,基础+增删改查+索引+聚合...

    一 基础了解 对应关系 -> https://docs.mongodb.com/manual/reference/sql-comparison/ database -> database ...

  3. MongoDB学习笔记—03 增删改查操作

    MongoDB的CURD操作分别通过函数insert().update().find().remove()进行 MongoDB文档新增与删除 MongoDB中关于文档的新增与删除比较简单.主要通过in ...

  4. SpringBoot学习笔记:Swagger实现文档管理

    SpringBoot学习笔记:Swagger实现文档管理 Swagger Swagger是一个规范且完整的框架,用于生成.描述.调用和可视化RESTful风格的Web服务.Swagger的目标是对RE ...

  5. MongoDB学习笔记(四) 用MongoDB的文档结构描述数据关系

    MongoDB的集合(collection)可以看做关系型数据库的表,文档对象(document)可以看做关系型数据库的一条记录.但两者并不完全对等.表的结构是固定的,MongoDB集合并没有这个约束 ...

  6. MongoDB学习-->命令行增删改查&JAVA驱动操作Mongodb

    MongoDB 是一个基于分布式文件存储的数据库. 由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关 ...

  7. Mongodb学习笔记四(Mongodb聚合函数)

    第四章 Mongodb聚合函数 插入 测试数据 ;j<;j++){ for(var i=1;i<3;i++){ var person={ Name:"jack"+i, ...

  8. 3、MyBatis.Net学习笔记之增删改

    增删改之前先说一下笔记1里提到的一个无法创建ISqlMapper对象的问题. <resultMaps> <resultMap id="FullResultMap" ...

  9. 【.NET-EF】Entity Framework学习笔记2 - 增删改(没查询)

    学习描述:用EF就像是省略了做实体类和DAL类,感觉是很方便,废话不多说,直接写步骤: 1.创建EF的edmx文件 这个其实在笔记1已说过,不过有些细节也要说,所以再说一遍,这里使用的是EF 6.1版 ...

随机推荐

  1. Python高手之路【六】python基础之字符串格式化

    Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-3101] This ...

  2. 深入理解C#

    简单认识.NET框架    (1)首先我们得知道 .NET框架具有两个主要组件:公共语言进行时CLR(Common Language Runtime)和框架类库FCL(Framework Class ...

  3. 23种设计模式--代理模式-Proxy

    一.代理模式的介绍       代理模式我们脑袋里出现第一个词语就是代购,其实就是这样通过一个中间层这个中间成是属于什么都干什么都买得,俗称"百晓生",在平时得开发中我们经常会听到 ...

  4. Objective-C中block的底层原理

    先出2个考题: 1. 上面打印的是几,captureNum2 出去作用域后是否被销毁?为什么? 同样类型的题目: 问:打印的数字为多少? 有人会回答:mutArray是captureObject方法的 ...

  5. 一起学微软Power BI系列-使用技巧(3)Power BI安卓手机版安装与体验

    Power BI有手机版,目前支持安卓,苹果和WP,不过没有WP手机,苹果在国内还不能用,要FQ和用就不测试了.安卓的我也也是费了九牛二虎之力才把app下载下来,把方法分享给大家. FQ太麻烦,所以建 ...

  6. app引导页(背景图片切换加各个页面动画效果)

    前言:不知不觉中又加班到了10点半,整个启动页面做了一天多的时间,一共有三个页面,每个页面都有动画效果,动画效果调试起来麻烦,既要跟ios统一,又要匹配各种不同的手机,然后产品经理还有可能在中途改需求 ...

  7. javascript之Object.defineProperty的奥妙

    直切主题 今天遇到一个这样的功能: 写一个函数,该函数传递两个参数,第一个参数为返回对象的总数据量,第二个参数为初始化对象的数据.如: var o = obj (4, {name: 'xu', age ...

  8. [.NET] 利用 async & await 进行异步 IO 操作

    利用 async & await 进行异步 IO 操作 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/6082673.html  序 上次,博主 ...

  9. 使用mybatis-generator在自动生成Model类和Mapper文件

    使用mybatis-generator插件可以很轻松的实现mybatis的逆向工程,即,能通过表结构自动生成对应的java类及mapper文件,可以大大提高工作效率,并且它提供了很多自定义的设置可以应 ...

  10. 微信公众号开发(一)--验证服务器地址的Java实现

    现在主流上都用php写微信公众号后台,其实作为后端语言之一的java也可以实现. 这篇文章将对验证服务器地址这一步做出实现. 参考资料:1.慕课网-<初识java微信公众号开发>,2.微信 ...