mongodb文档的CRUD
本章会介绍对数据库移入或者移出数据的基本操作
- 向集合添加文档
- 从集合删除文档
- 更新现有的文档
- 为这些操作选择合适的安全级别
添加删除数据库
添加数据库 :use foo 如果存在foo 就use 不存在就创建foo
删除数据库 1 use 数据库名 2 db.dropDatabase()
插入并保存文档向集合插入文档,并且查询文档 代码 :
db.foo.insert() foo就是集合 如果不存在创建集合foo insert 就是想这个集合添加文档 find 进行查询 返回的数据中的"_id"是mongodb自动添加的 唯一重复的键
可以批量插入 他接受一个文档数组作为参数
db.foo.batchInsert([{"name":"w"},{"name":"d"},{"name":"r"}])
一次发送数十 数百乃至数千个文档会明显提高插入速度 只有将多个文档插入一个集合时 才有用 如果批量插入的过程中插入失败 那么在这个文档之前的所有操作都会成功插入集合中,而这个文档以及之后的所有文档全部插入失败
插入校验
在文档插入时 mongodb只会对数据进行最基本的检查:检查文档的基本机构 没有_id 自动增加一个 检查大小 所有文档都必须小于16M 主流语言的驱动程序都会在数据插入数据库之前做大量的数据校验
删除文档
db.foo.remove() 清空foo集合中的所有数据
可以接受一个查询文档作为参数 删除数据是永久性的 不能撤销 也不能恢复
删除文档通常很快 但是要清空集合 那么使用drop直接删除结合会更快
db.foo.drop()
更新文档
文档插入数据库以后 就可以使用update方法更新他 update有两个参数 一个是查询文档 用于定位需更新的文档 一个是修改器文档 用于说明要对找到的文档进行那些修改
先到先更新 后到的取得胜利
最简单的更新就是用一个新的文档替换匹配文档 适用于大规模的数据迁移
db.foo.insert({"name":"joe","friends":32,"enemies":2})
我们希望将 friends enemies 两个字段移到 relationships子文档 可以在上shell中改变文档的机构 然后用update替换数据库中的当前文档
var joe = db.foo,findOne({"name":"joe"})
joe.relationships = {"friends":joe.friengs,"enemies":joe.enemies}
joe.username = joe.name
delete joe.friengs
delete joe.enemies
delete joe.name
db.foo.update({"name":"joe"},joe)
使用修改器
通常文档只会有一部分要更新 可以使用原子性的更新修改器 指定对文档中的某些字段进行更新 更新修改器 是中特殊的键 用来指定复杂的更新操作 比如修改 增加 删除键 还可能是操作数组或者内嵌文档
$inc 只能操作值是数字的建 这个这个建存在 +或者- 不存在创建 对于更新数据 因果关系 投票 或者其他有变化的数值的地方 很方便
假设要在一个集合中放置网站的分析数据 只要个人访问页面 就增加计数器 可以使用更新奇原子性完成这个增加 每个URL及对应的访问次数都可以如下格式存储文档中
db.foo.insert({"url":"www","pageviews":52})
db.foo.upate({"url":"www"},{"$inc":{"pageviews":1}})
db.foo.find({"url":"www"})
注意 _id的值是不能改变的 使用修改器时
$set 修改器入门
用来指定一个字段的值 如果这个字段不存在 创建它 这对更新模式或者增加用户定义的键来说非常方便
{"name":"joe","age":30,"sex":"male","locarion":"wisconsin"}
想要添加喜欢的书籍进去 可以使用“$set”
db.users.upate(criteria,{"$set":{"favorite book":"War and peace"}})
这样文档中 就有了favorite book这个键了
要是用户觉得喜欢的是另外一本书
db.users.upate(criteria,{"$set":{"favorite book":"Green Eggs and ham"}}) 据说这本书 是用五十个英文词汇 写成的书
$set 甚至可以修改键的类型 用户觉得自己喜欢很多书
db.users.upate(criteria,{"$set":{"favorite book":["ender's Game","cat's cradle"]}})
突然用户不爱读书了 db.users.upate(criteria,{"$unset":{"favorite book":1}})
也可以用这个修改器 来修改内嵌文档 格式
{"title":"A Blog Post","content":"sdeadfe","author":{"name":"joe","email":"joe@esample.com"}}
{"$set":{"author.name":"joe shmoe"}}
数组修改器
有一类很重要的修改器可用于操作数组, 数组是常用且非常有用的数据结构
添加元素 $push 如果数组已经存在 会在末尾添加一个元素 如果不存在就创建一个新的数组
db.foo.update({"title":"A blog post"},{"$push":{"comments":{"name":""joe,"email":"joe@exmple.com","content":"nice post"}}})
在执行一次 就在添加一条
这种$push 使用形式 比较单一 也可以将他应用到比较复杂的数组操作 使用$each 子操作符 可以通过一次$push 添加多个值
{"$push":{"hourly":{"$each":[572,567,231.123]}}} 这样可以将三个元素添加到数组中 如果希望数组的长度是固定的 那么就需要$slice和$push 组合在一起使用
{"$push":{"top10":{"$each":["大苏打","sdww"],"$slice":-10}}} 会限制数组只包含最后加入的10个元素 $slice值 必须是负数 如果添加的元素个数小10 全部添加 大于10 保留最后10个元素
$slice 与 $push配合使用 且 必须使用$each
$push 一次只能为数组添加一个值,与$each结合可以一次添加多个值,和$slice 结合使用 可以限制添加值的个数
将数组避免重复添加
$addToSet 避免重复添加 存在不操作 不存在添加
{"addToSet":{"emails":{"$each":["joe@php.net","joe@example.com","joe@python.org"]}}}
删除元素
有几个从数组删除元素的方法 若把数据看成队列 或者栈 可以用 $pop 从一端删除元素 {"$pop":{"key":1}} 从末尾删除一个元素 {"$pop":{"key":-1}}从头删除一个元素
有时需要特定条件删除元素 不仅仅基于位置 可以使用"$pull"
{"rodo":["dishes","laundry","dry cleaning"]}
update({},{"$pull":{"todo":"laundry"}})
这个修改器 会将匹配到的文档都全部删除 而不是删除一个 对于数组 [1.1.2.1] 执行pull 1 结果[2]
基于位置的数组修改器
有两种方法操作数组中的值 :通过位置 或者定位符$ 数组的下标都以0开头 可以将下标直接作为键来选择元素
数据模型 :
{
"content":"摄师傅",
"comments":[{
"comment":"good post"
"author" : "john"
"votes" : 0
},{
"comment":"i thought it was to short"
"author" : "claire"
"votes" : 3
},{
"comment":"free watches"
"author" : "alice"
"votes" : -1
}]
}
"content":"摄师傅",
"comments":[{
"comment":"good post"
"author" : "john"
"votes" : 0
},{
"comment":"i thought it was to short"
"author" : "claire"
"votes" : 3
},{
"comment":"free watches"
"author" : "alice"
"votes" : -1
}]
}
{"$inc":{"comments.0.votes":1}}
很多情况下 我们不预先查询文档就不能知道要修改的数组下标 为了客服这个困难 mongoDB提供了定位操作符"$" 用来定位查询已经匹配的数组元素并进行更新 例如 用户john把名字改成jim
update({"comments.author":"john"},{"$set":{"comments.$author":"Jim"}})
定位符只更新第一个匹配的元素 如果John发表了多条评论 那么他的名字只在第一条评论中改变
upsert 是一种特殊的更新 要是没有找到符合更新条件的文档机会以这个条件和更新文档为基础穿件一个新的文档 如果找到了匹配的文档 这正常更新 upsert非常方便 不必预置集合
update 的第三个参数 设置成true 就是upsert
需要创建文档的同时创建字段并赋值 但是之后的所有更新操作中 这个字段的值不会改变 这就是$setOnInsert的作用
update({},{"$setOnInsert":{"createAt":new Date()}},true)
再次运行这个语句 会匹配到一存在的文档 所以不会再插入文档 因车createAt 这个字段的值 也饿不会改变
返回被更新的文档
findAndModify 这个方法对于操作队列以及执行其他需要进行原子性取值和辅助的操作十分的方便
代码示例:
ps = db.runCommand({'findAndModify':'pocesses','query':{'status':'READY'},'sort':{"priority":-1},'update':{"$set":{"status":"RUNNING"}}} ).value
在findAndModify 中可以使用的字段
- findAndModify 集合名
- query 查询文档
- sort 排序
- update 修改器文档 用于对匹配的文档更新
- remove 布尔型 是否删除文档
- new 布尔型 返回更新前的文档还是更新后的 默认返回更新前的
- fields 文档中需要返回的字段
- upsert 布尔型 true是upsert 默认是false
update和remove 必须有一个
save shell 帮助程序 save 是一个shell函数 如果文档不存在 自动创建文档 存在更新文档 他只有一个参数 文档 要是这个文档中包含_id save会调用upsert 否则会调用insert
var x = db.foo.findOne()
x.unm = 42
db.foo.save(x)
默认情况下 更新只能对符合匹配条件的第一个文档执行操作 要是有多个文档符合条件 只有第一个文档呗更新 其他文档不会有变化 要更新所有匹配的文档 可以将update的第4个参数设置为true
要知道这条update程序 更新了多少文档 db.runCommand({getLastError:1})
返回的值中 n键的值 就是被更新的文档数量