MongoDB学习笔记4

MongoDB学习笔记4

使用修改器(Update modifier)

更新文档中的某些字段(要是没有就创建一个)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//假设要在一个集合中放置网站的分析数据,只要有人访问页面就增加计数器
{
“_id” : ObjectId("jianyhaomnrdncy69227"),
"url" : "1-riverfish.github.io",
"pageviews" : 973
}

> db.analytics.update({"url":"1-riverfish.github.io"},{"$inc" : {"pageviews" : 1}})

>db.analytics.find()
{
“_id” : ObjectId("jianyhaomnrdncy69227"),
"url" : "1-riverfish.github.io",
"pageviews" : 974
}

使用修改器时,“_id”的值不能改变。

$set修改器入门

“$set” 用来指定一个字段的值,如果这个字段不存在,则创建它。

“$unset” 用来删除键。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
> db.analitics.update({"_id":ObjectId("59cce76a1ad2fc6e3b5d138f")},{"$set":{"theme":"personal blog"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.a
> db.analitics.find()
{ "_id" : ObjectId("59cce76a1ad2fc6e3b5d138f"), "url" : "1-riverfish.github.io", "pageviews" : 974, "theme" : "personal blog" }

//更改博客主题
> db.analitics.update({"_id":ObjectId("59cce76a1ad2fc6e3b5d138f")},{"$set":{"theme":"passage blog"}})

//修改键的类型
> db.analitics.update({"_id":ObjectId("59cce76a1ad2fc6e3b5d138f")},{"$set":{"theme":["passage blog","personal blog","interesting blog"]}})

//删除键
> db.analitics.update({"_id":ObjectId("59cce76a1ad2fc6e3b5d138f")},{"$unset":{"theme":1}})

// 用"$set"修改内嵌文档
> db.analitics.update({"_id":ObjectId("59cce76a1ad2fc6e3b5d138f")},{"$set":{"_posts.passage":"MongoDB学习笔记1"}})
> db.analitics.update({"_id":ObjectId("59cce76a1ad2fc6e3b5d138f")},{"$set":{"_posts.name":"Mongo学习笔记"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.analitics.find()
{ "_id" : ObjectId("59cce76a1ad2fc6e3b5d138f"), "url" : "1-riverfish.github.io", "pageviews" : 974, "theme" : [ "passage blog", "personal blog", "interesting blog" ], "_posts" : { "name" : "Mongo学习笔记" } }

一定要使用 $ 开头的修改器来修改 键/值 对。

$inc增加和减少

$inc 修改器用来增加已有键的值,或者该键不存在那就创建一个。对于更新分析数据,因果关系,投票或者其他有变化数值的地方,使用这个都会非常方便。

$inc 只能用于整型,长整型或者双精度浮点型,用在其他类型的数据上就会导致操作失败。

数组修改器

  • $push

向已有的数组末尾加入一个元素,要是没有就创建一个新的数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
> db.web.update({"_id":ObjectId("59ccf35f20f6170fe3733a71")},{"$push":{"comments":{"name":"ginger","comment":"good post"}}})

> db.web.findOne()
{
"_id" : ObjectId("59ccf35f20f6170fe3733a71"),
"theme" : "Mongo",
"comments" : [
{
"name" : "ginger",
"comment" : "good post"
}
]
}

//再添加一条评论
> db.web.update({"_id":ObjectId("59ccf35f20f6170fe3733a71")},{"$push":{"comments":{"name":"1-riverfish","comment":"good job!"}}})
> db.web.findOne()
{
"_id" : ObjectId("59ccf35f20f6170fe3733a71"),
"theme" : "Mongo",
"comments" : [
{
"name" : "ginger",
"comment" : "good post"
},
{
"name" : "1-riverfish",
"comment" : "good job!"
}
]
}

使用 “$each” 子操作符,可以通过一次 \$push操作添加多个数值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
> db.web.update({"_id":ObjectId("59ccf35f20f6170fe3733a71")},{"$push":{"comments":{"$each":[{"name":"smallfish","comment":"good!"},{"name":"flyingfish","comment":"nice"}]}}})
> db.web.findOne()
{
"_id" : ObjectId("59ccf35f20f6170fe3733a71"),
"theme" : "Mongo",
"comments" : [
{
"name" : "ginger",
"comment" : "good post"
},
{
"name" : "1-riverfish",
"comment" : "good job!"
},
{
"name" : "smallfish",
"comment" : "good!"
},
{
"name" : "flyingfish",
"comment" : "nice"
}
]
}

如果希望数组的最大长度是固定的,那么可以将“$slice”和“\$push”组合在一起使用。

限制数组包含最后加入的10个元素,而且”$slice”的值必须是负整数。

将数组作为数据集使用

$addToSet

1
2
3
4
> db.users.update({"_id":ObjectId("59ce00dd2fb5bdebacb51f22")},
... {"$addToSet":{"e-mails":{"$each": ["6.qq.com","10.qq.com"]}}})
> db.users.find()
{ "_id" : ObjectId("59ce00dd2fb5bdebacb51f22"), "username" : "1-riverfish", "e-mails" : [ "1.qq.com", "2.163.com", "3.github.com", "6.qq.com", "10.qq.com" ] }

删除元素

$pop 这个修改器可以从数组任何一端删除元素

$pull 基于特定条件删除数组中的元素

1
2
3
4
db.lists.insert({"todo":["dishes","laundry","dry cleaning"]})
{“$pop”:{"key":-1}} //从数组头部删除
{“$pop”:{"key":1}} //从数组末尾删除
db.lists.update({},{“$pull”:{"todo":"laundry"}}) //基于特定条件删除元素

基于位置的数组修改器

若是数组有多个值,而我们只想对其中的一部分进行操作,有两种操作:通过位置或者定位操作符 $

1
2
db.blog.update({"comments.author":"ginger"},
... {"$set":{"comments.$.author":"1-riverfish"}})

定位符只更新第一个元素

修改器速度

upsert

upsert 是一种特殊的更新,要是没有找到符合更新条件的文档,就会以这个条件和更新文档为基础创建一个文档,如果找到了了匹配的文档,则正常更新。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//记录网站页面访问次数的例子
blog = db.analytics.findOne({"url":"/blog"})

if(blog){
blog.pageviews++;
db.analytics.save(blog);
}
else
{
db.analytics.save({"url":"/blog",pageviews:1})
}

//如果使用 upsert,既可以避免竞态问题,又可以缩减代码量,update的第三个参数表示这是个 upsert
db.analytics.update({"url":"/blog"},{"$inc":{"pageviews":1}},true);

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

1
db.users.update({},{"$setOnInsert":{"createAt": new Date()}},true);

save shell帮助程序

save 是一个shell函数,如果文档不存在,它会自动创建文档;如果文档存在,就更新这个文档。它只有一个参数,文档。要是这个文档含有”_id”键,save会调用upsert,否则会调用 insert.

更新多个文档

默认更新符合匹配条件的第一个文档,要更新所有的文档,可以将update的第四个参数设置为 true.

建议每次都显示地表明要不要做多文档更新。

1
2
//多文档更新对模式迁移非常有用,还可以对特定用户发布新功能时使用
> db.users.update({"birthday":"5/11/1998"},{"$set":{"gift":"Happy Birthday!"}},false,true)

getLastError命令查看更新了多少文档(可以理解为“返回最后一次操作的相关信息”)。键 “n” 的值就是被更新的文档的数量。

1
> db.runCommand({getLastError:1})

返回被更新的文档

findAndModify 命令

  • findAndModify 字符串 集合名
  • query 查询文档,用于检索文档的条件
  • sort 排序结果的条件
  • update 修改器文档,用于对匹配的文档进行更新(update 与 remove必须指定一个)
  • remove 布尔类型,表示是否删除文档
  • new 布尔类型,表示返回更新前的文档还是更新后的文档。默认是更新前的文档。
  • fields 文档中需要返回的字段(可选)
  • upsert 布尔类型,值为true时表示这是一个upsert,默认为false

写入安全机制(Write Concern)

写入安全是一种客户端设置,用于控制写入的安全级别。默认情况下,插入,删除,更新都会一直等待数据库的响应(写入是否成功),然后才会继续执行。通常,遇到错误时,客户端会抛出一个异常。

  • 应答式写入(acknowledged write)
  • 非应答式写入(unacknowledged write)

Any question please contact 1-riverfish