$slice

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

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

db.class.insert({"班级":"1班"})

WriteResult({ "nInserted" :  })
> db.class.update(
... {"班级":"1班"},
... {"$push":{"students":{
... "$each":["zs","ls","ww"],
... "$slice":-}}})
WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
> db.class.findOne()
{
"_id" : ObjectId("5854b5a0e7d717fcb974637b"),
"班级" : "1班",
"students" : [
"zs",
"ls",
"ww"
]
} > db.class.update(
... {"班级":"1班"},
... {"$push":{"students":{
... "$each":["yyb","rhr","www","qqq","eee","rrr"],
... "$slice":-}}})
WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
> db.class.findOne()
{
"_id" : ObjectId("5854b5a0e7d717fcb974637b"),
"班级" : "1班",
"students" : [
"rhr",
"www",
"qqq",
"eee",
"rrr"
]
}
>

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

> db.class.update({},{ "班级" : "一班"})
WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
> db.class.update(
... {"班级":"一班"},
... {"$push":{"students":
... {"$each":[{"name":"aaa","age":},{"name":"bbb","age":},{"name":"ccc","age":}],
... "$slice":-,
... "$sort":{"age":-}}}})
WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
> db.class.findOne()
{
"_id" : ObjectId("5854b5a0e7d717fcb974637b"),
"班级" : "一班",
"students" : [
{
"name" : "bbb",
"age" :
},
{
"name" : "aaa",
"age" :
}
]
}
>

$ne与$addToSet

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

> db.papers.insert({"authors cited":["yyb"]})
WriteResult({ "nInserted" : })
> db.papers.update({"authors cited":{"$ne":"Richie"}}, {"$push":{"authors cited":"Richie"}})
WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
> db.papers.findOne()
{
"_id" : ObjectId("5854c900e7d717fcb974637e"),
"authors cited" : [
"yyb",
"Richie"
]
}
> db.papers.update({"authors cited":{"$ne":"Richie"}}, {"$push":{"authors cited":"Richie"}})
WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
>
 db.user.findOne()
{
"_id" : ObjectId("5854cb40e7d717fcb974637f"),
"username" : "joe",
"emails" : [
"joe@example.com",
"joe@gmail.com",
"joe@yahoo.com"
]
} > db.user.update(
... ... {"username":"joe"},
... ... {"$addToSet":{"emails":"joe@gmail.com"}})
WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
> db.user.update(
... ... ... {"username":"joe"},
... ... ... {"$addToSet":{"emails":"joe@hotmail.com"}})
WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
> db.user.findOne()
{
"_id" : ObjectId("5854cb40e7d717fcb974637f"),
"username" : "joe",
"emails" : [
"joe@example.com",
"joe@gmail.com",
"joe@yahoo.com",
"joe@hotmail.com"
]
}
>

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

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

>db.user.insert({ "username" : "joe"})
> db.user.update(
... {"username" : "joe"},
...
... {"$addToSet":
... {"emails" :{"$each": [
... "joe@example.com",
... "joe@gmail.com",
... "joe@yahoo.com",
... "joe@hotmail.com",
... "joe@hotmail.com"]}}})
WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
> db.user.findOne()
{
"_id" : ObjectId("5854ce5ce7d717fcb9746380"),
"username" : "joe",
"emails" : [
"joe@example.com",
"joe@gmail.com",
"joe@yahoo.com",
"joe@hotmail.com"
]
}
>

从数组中删除元素

$pop

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

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

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

> db.class.findOne()
{
"_id" : ObjectId("5854b5a0e7d717fcb974637b"),
"班级" : "一班",
"students" : [
{
"name" : "bbb",
"age" :
},
{
"name" : "aaa",
"age" :
}
]
}
> db.class.update(
... {"班级" : "一班"},
... {"$pop":{"students":}})
WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
> db.class.findOne()
{
"_id" : ObjectId("5854b5a0e7d717fcb974637b"),
"班级" : "一班",
"students" : [
{
"name" : "bbb",
"age" :
}
]
}
>

$pull

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

> db.list.insert(
... {"todo":["dishes","laundry","dry cleaning"]})
WriteResult({ "nInserted" : })
> db.list.update({},{"$pull":{"todo":"laundry"}})
WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
> db.list.findOne()
{
"_id" : ObjectId("585690afc5b0525a48a441b4"),
"todo" : [
"dishes",
"dry cleaning"
]
}
>

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

基于位置的数组修改器

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

位置

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

> db.blog.insert(
... {
... "content": "...",
... "comments": [
... {
... "comment": "good post",
... "author": "john",
... "votes":
... },
... {
... "comment": "i thought it was too short",
... "author": "claire",
... "votes":
... },
... {
... "comment": "free watches",
... "author": "alice",
... "votes": -
... }
... ]
... })
WriteResult({ "nInserted" : }) > db.blog.update({"content":"..."},{"$inc":{"comments.0.votes":}})
WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
> db.blog.findOne()
{
"_id" : ObjectId("585694e4c5b0525a48a441b5"),
"content" : "...",
"comments" : [
{
"comment" : "good post",
"author" : "john",
"votes" :
},
{
"comment" : "i thought it was too short",
"author" : "claire",
"votes" :
},
{
"comment" : "free watches",
"author" : "alice",
"votes" : -
}
]
}
>

定位操作符$

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

> db.blog.update(
... {"comments.author":"john"},
... {"$set":{"comments.$.author":"jim"}})
WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
> db.blog.findOne()
{
"_id" : ObjectId("585694e4c5b0525a48a441b5"),
"content" : "...",
"comments" : [
{
"comment" : "good post",
"author" : "jim",
"votes" :
},
{
"comment" : "i thought it was too short",
"author" : "claire",
"votes" :
},
{
"comment" : "free watches",
"author" : "alice",
"votes" : -
}
]
}
>

upsert

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

> db.analytics.update({"url":"/blog"},{"$inc":{"pageviews":}},true)
WriteResult({
"nMatched" : ,
"nUpserted" : ,
"nModified" : ,
"_id" : ObjectId("58569d3cb6687ca8dfad4e01")
})
> db.analytics.findOne()
{
"_id" : ObjectId("58569d3cb6687ca8dfad4e01"),
"url" : "/blog",
"pageviews" :
}
> db.analytics.update({"url":"/blog"},{"$inc":{"pageviews":}},true)
WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
> db.analytics.findOne()
{
"_id" : ObjectId("58569d3cb6687ca8dfad4e01"),
"url" : "/blog",
"pageviews" :
}
>

$setOnInsert

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

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

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

> db.user.update({},{"$setOnInsert":{"createAt":new Date()}},true)
WriteResult({
"nMatched" : ,
"nUpserted" : ,
"nModified" : ,
"_id" : ObjectId("58569fe1b6687ca8dfad4e02")
})
> db.user.findOne()
{
"_id" : ObjectId("58569fe1b6687ca8dfad4e02"),
"createAt" : ISODate("2016-12-18T14:40:33.273Z")
}
> db.user.update({},{"$setOnInsert":{"createAt":new Date()}},true)
WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
> db.user.findOne()
{
"_id" : ObjectId("58569fe1b6687ca8dfad4e02"),
"createAt" : ISODate("2016-12-18T14:40:33.273Z")
}
>

save

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

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

> db.user.save({"x":,"y":})
WriteResult({ "nInserted" : })
> var x=db.user.findOne()
> x.num= > db.user.save(x)
WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
> db.user.findOne()
{
"_id" : ObjectId("5856a230c5b0525a48a441be"),
"x" : ,
"y" : ,
"num" :
}

更新多个文档

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

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

> db.coll.find()
{ "_id" : ObjectId("5856994bc5b0525a48a441b9"), "x" : "a" }
{ "_id" : ObjectId("58569966c5b0525a48a441ba"), "x" : "bbb" }
{ "_id" : ObjectId("5856996fc5b0525a48a441bb"), "x" : "c" }
> db.coll.update({},{"$set":{"x":}},false,true )
WriteResult({ "nMatched" : , "nUpserted" : , "nModified" : })
> db.runCommand({getLastError:})
{
"connectionId" : ,
"updatedExisting" : true,
"n" : ,
"syncMillis" : ,
"writtenTo" : null,
"err" : null,
"ok" :
}
>

返回被更新的文档

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

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

 ps=db.runCommand({"findAndModify":"processes", "query":{"status":"ready"},
"sort":{"pirority":-},
"update":{"$set":{"status":"Running"}}})
{
"lastErrorObject" : {
"updatedExisting" : true,
"n" :
},
"value" : {
"_id" : ObjectId("5857c939d7a32a888bd79c47"),
"pirority" : ,
"status" : "ready"
},
"ok" :
}
> db.processes.findOne("_id":ps.value._id)
--19T19::04.904+ E QUERY [thread1] SyntaxError: missing ) after argument list @(shell):: > db.processes.findOne({"_id":ps.value._id})
{
"_id" : ObjectId("5857c939d7a32a888bd79c47"),
"pirority" : ,
"status" : "Running"
}
>

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

> ps=db.runCommand({"findAndModify":"processes", "query":{"status":"ready"},
"sort":{"priority":-},
"remove":true}).value
{
"_id" : ObjectId("5857c9b1d7a32a888bd79c48"),
"pirority" : ,
"status" : "ready"
} > db.processes.findOne({"_id":ps._id})
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. [高并发]Java高并发编程系列开山篇--线程实现

    Java是最早开始有并发的语言之一,再过去传统多任务的模式下,人们发现很难解决一些更为复杂的问题,这个时候我们就有了并发. 引用 多线程比多任务更加有挑战.多线程是在同一个程序内部并行执行,因此会对相 ...

  2. 谈谈如何使用Netty开发实现高性能的RPC服务器

    RPC(Remote Procedure Call Protocol)远程过程调用协议,它是一种通过网络,从远程计算机程序上请求服务,而不必了解底层网络技术的协议.说的再直白一点,就是客户端在不必知道 ...

  3. 懒加载session 无法打开 no session or session was closed 解决办法(完美解决)

           首先说明一下,hibernate的延迟加载特性(lazy).所谓的延迟加载就是当真正需要查询数据时才执行数据加载操作.因为hibernate当中支持实体对象,外键会与实体对象关联起来.如 ...

  4. BootStrap_02之全局样式及组件

    1.BootStrap指定的四种屏幕尺寸: ①超大PC屏幕--lg(large):w>=1200px: ②中等PC屏幕--md(medium):1200px>w>=992px: ③P ...

  5. angular2系列教程(十一)路由嵌套、路由生命周期、matrix URL notation

    今天我们要讲的是ng2的路由的第二部分,包括路由嵌套.路由生命周期等知识点. 例子 例子仍然是上节课的例子:

  6. spring源码分析之context

    重点类: 1.ApplicationContext是核心接口,它为一个应用提供了环境配置.当应用在运行时ApplicationContext是只读的,但你可以在该接口的实现中来支持reload功能. ...

  7. Mysql命令大全

    格式: mysql -h主机地址 -u用户名 -p用户密码 1.连接到本机上的MYSQL.首先打开DOS窗口,然后进入目录mysql\bin,再键入命令mysql -u root -p,回车后提示你输 ...

  8. Oracle 数据库知识汇总篇

    Oracle 数据库知识汇总篇(更新中..) 1.安装部署篇 2.管理维护篇 3.数据迁移篇 4.故障处理篇 5.性能调优篇 6.SQL PL/SQL篇 7.考试认证篇 8.原理体系篇 9.架构设计篇 ...

  9. CSS 3学习——transform 2D转换

    首先声明一点,transform属性不为none的元素是它的定位子元素(绝对定位和固定定位)的包含块,而且对内创建一个新的层叠上下文. 注意:可以通过 transform-box 属性指定元素的那个盒 ...

  10. MyBatis源码分析(一)开篇

    源码学习的好处不用多说,Mybatis源码量少.逻辑简单,将写个系列文章来学习. SqlSession Mybatis的使用入口位于org.apache.ibatis.session包中的SqlSes ...