MongoDB 插入概览
插入文档
当执行插入的时候,使用的驱动程序会将数据转换为
BSON
格式,如果文档中没有定义id
,则MongoDB
会自动生成id
BSON
:MongoDB
的文档内部数据格式,BSON
的优点有:
- 更快的遍历速度,
BSON
会将每个元素的长度存在元素头部,增加遍历速度- 更简单的操作
- 更多的数据类型
- 基本插入(
id
存在会报错)
db.foo.insert({"bar":"baz"})
- 存在则更新
db.foo.save({"bar":"baz"})
- 批量插入
db.foo.insert(
[
{"bar":"baz"},
{"boo":"bzz"}
]
)
当批量插入的时候,
insert
和save
没有区别
db.foo.insertMany([
{"bar":"baz"},
{"boo":"bzz"}
])
删除文档
MongoDB
删除文档会很快,但是如果要清楚整个集合,那么直接删除集合(然后重建索引)会更加快
- 基础删除
//删除所有文档,但是会保留集合本身
db.users.remove({})
- 指定条件删除
//默认会删除所有符合条件的
db.users.remove({"_id":12345})
//仅仅删除第一条符合条件的数据
db.users.remove({"_id":12345},true)
更新文档
- 全量覆盖更新
db.users.update({"_id":12345},newUser)
注意:由于
update
第一个参数所匹配的元素可能有多个,因此可能导致最后修改的元素不是想要修改的哪一个,此时最好指定一个唯一元素,例如:_id
- $inc 增加
//将用户年龄增加3岁
db.users.update({"_id":12345},
{"$inc":{"age":3}
})
- $set 设置字段和值/如果字段不存在则添加,如果字段存在则修改
//为users添加一个favorite book 字段
db.users.update(
{"_id":12345},
{"set":{"favorite book": "war and peace"}}
)
//添加内嵌字段
db.users.update(
{"_id":12345},
{"set":{"author":{"name":"joe"}}}
)
- $unset 删除字段
db.users.update(
{"_id":12345},
{"$unset":{"favorite book": 1}}
)
- $push 给数组添加一个字段 / 只能用于数组,若数组不存在,则创建
注意,默认数组不会判重
db.users.update(
{"_id":12345},
{"$push":{"comments":"6666"}}
)
- $addToSet 如果数组不存在此字段则添加,存在则不添加
db.users.update(
{"_id":12345},
{"$addToSet":{"comments":"6666"}}
)
- $each 给数组添加多个值(只能与
push
或addToSet
组合使用)
db.users.update(
{"_id":12345},
{"addToSet":{"comments":"each":["6666","777"]}}
)
- $pop 删除数组任何一端元素
//从末尾删除
db.users.update(
{"_id":12345},
{"pop":{"comments":1}}
)
//从头部删除
db.users.update(
{"_id":12345},
{"pop":{"comments":-1}}
)
只能为1或-1
- $pull 删除指定元素
db.users.update(
{"_id":12345},
{"$pull":{"commentes":"6666"}}
)
- $ 数组坐标访问
db.users.update(
{"comments.author":"dcc"},
{"set":{"comments..author":"dcc2"}}
)
- upsert 存在则更新,不存在则覆盖
//原本的代码:
user = db.users.findOne({"_id":"1234"});
if(blog){
blog.times++;
db.users.save(blog);
}else{
db.users.save({"_id":"1234","times":1})
}
//使用upsert
db.users.update({"_id":"1234",{"$inc":{"times":1}}},true)
使用
upsert
可以避免竞态问题
- 批量更新
默认情况下,
update
只会更新第一个匹配到的文档,如果想要批量更新,可以将update
第四个条件设置为true
db.users.update({"name":dcc},{"$set":{"name":"dcc2"}},false,true)
可以通过
db.runCommand({getLastError:1})
查看具体修改了多少个数据注意:当第三个参数为
true
的时候,批量更新不会生效,而会创建
findAndModify
由于
update
不是一个原子操作,而有些时候需要先查找,然后修改,然后再对返回的数据进行一定的操作,如果需要查找和修改作为一个原子操作的话,可以使用findAndModify
db.mulit.findAndModify({
query:{"x":12345},
update:{"$set":{"x":123456}},
upsert:true,
new:false
})
可以通过
new
来控制返回修改前的属性还是修改后的属性可以通过增加
sort
选项来确定所修改的元素,findAndModify
只会修改并返回第一个文档
查询文档
- 基础查询
db.users.find({"_id":"123123"})
db.users.find({"_id":"123123","age":18})
- 只返回指定的键
//需要返回的值包括 username 和 email
db.users.find({},{"username":1,"email":1})
//需要返回的值不包括 username
db.users.find({},{"username":0})
//需要返回值不包括_id
db.users.find({},{"_id":0})
不管有没有指定
_id
,它都会直接返回
- 查询条件
$lt (less than) $lte (less than equals) $gt (greater than) $gte (greater than equals)
//查找年龄小于18岁的用户
//不包含此字段的元素不会返回
db.users.find({"age":{"$lt",18}})
$ne not equals
反向查询
//查找年龄不为17的用户
//不包含此字段的元素也会返回
db.users.find({"age":{"$ne":17}})
$in
批量查询
//查找年龄为18 或 12 的用户
db.users.find({"age":{"$in":[12,18]}})
$nin
批量反向查找
//查找年龄不为18 或 12 的用户
db.users.find({"age":{"$nin":[12,18]}})
$or
多条件查询
//查找年龄为18 或者名字为dcc的用户
db.users.find({"or":[{"age":18},["name":"dcc"]])
$not
反向逻辑查找
//查找年龄不大于18的用户
//not 只能与其他元操作符连起来使用
db.users.find({"age":{"not":"gt":18}})
- 查找字段为
null
db.users.find({"name":{"in":[null],"exists":true}})
- 正则表达式
//查找所有姓名以d开头的用户
//注意正则表达式不用引号
db.users.find({"name":/d.*/})
- 查询数组
数组中的元素查询可以直接通过任意元素即可匹配
//查找包含dcc的数组
db.users.find({"comments":"dcc"})
$all
查询数组同时包含的元素
//查找数组中同时包含`dcc`和 `dcc2`的元素
db.users.find({"comments":{"$all":["dcc","dcc2"]}})
如果不是用
all
,那么这个数组的元素顺序,数量必须相同
.数字
通过数组下标匹配
//查找comments 数组第二个元素为dcc的文档
db.users.find({"comments.2":"dcc")
$size
匹配数组元素大小
//查找`comments` 数组大小为3 的文档
db.users.find({"comments":{"$size":3}})
$slice
切割数组
//查找`id`为123 的文档的前10条评论
db.users.find({"_id":123},{"comments":{"slice":10}})
//查找`id`为123 的文档的 后10条评论
db.users.find({"_id":123},{"comments":{"slice":-10}})
//查找`id`为123 的文档的 后10-20条评论
db.users.find({"_id":123},{"comments":{"$slice":[10,10]}})
- 查询内嵌文档
{
"name":{
"first":"Joe",
"last":"Schmoe"
}
}
db.users.find({"name":{"first":"Joe","last":"Schmoe"}})
db.users.find({"name.first":"Joe","name.last":"Schmoe"})
注意:内嵌文档需要完全匹配
eg.
有如下文档:
{
"comments": [{
"name": "dcc1",
"age": 18
}, {
"name": "dcc2",
"age": 19
}, {
"name": "dcc3",
"age": 20
}]
}
则如果想要查找某个comments
中包含某个元素,年龄小于等于18并且名为dcc
如果使用:
db.users.find({"comments.name":"dcc1","comments.age":{"$lte":18}})
会返回上面的文档,但是上面的文档并不满足要求。
此时可以使用
$elemMatch
表示匹配单个内嵌文档的条件
db.user.find({"commnets":{"elemMatch":{"name":"dcc","age":{"lte":18}}})
对返回结果的处理:
limit
限制返回的数量
//仅仅返回前3个结果
db.users.find().limit(3)
skip
跳过元素
//跳过3个元素
db.users.find().skip(3)
sort
对结果进行排序,1 升序, -1 降序
db.users.find().sort({"username":1,"age":-1})
注意,使用
skip
跳过大量文档的时候,会带有性能问题,解决方案可以通过sort()
加上比较符进行跳转,也能达到skip
的效果,并且没有性能问题