最近做的几个项目都用到了mongodb
和mongoose
,以前整理过一份常用api
,重温一次再做补充。
shell
- show dbs,show databases
- show collections,show tables
- show users
- show profile
- use \
- db.help()
- db.auth
- db.addUser
数据类型
- null
- boolean
- 64位浮点数(js),32位整数,64位整数,64位浮点数
- string
- date
- ObjectId
- regexp
- code javascript代码
- buffer
- undefined
- array
- document
- max/min
ObjectId() 12字节存储,每个字节两位16进制数字。
0-3字节位时间戳,4-6字节主机唯一标示,7-8位pid标识不同进程,9-11位计数器。
所以同一秒同一进程最多可产生256^3(16777216)个不同的ObjectId。
mongodb中不存储时区,从标准纪元开始的ms数。shell显示时会读取本地的时区设置做对应转换。
基本操作接口
curd
create
post = {}
db.blog.insert(post);
update
post = {content:’test’}
db.blog.update({title:”post”},post);
find
db.blog.find({title:”post”})
remove
db.blog.remove({title:”post”});
插入
db.foo.insert({“bar”:”baz”});
对同一集合插入时,尽量使用批量插入,但是批量插入消息长度最大为16MB。
单个文档(转换为BSON)不能大于4MB。shell中使用 Object.bsonsize(doc)查看大小。
删除文档
db.users.remove([optional doc]) 删除users集合中所有文档,但不会删除集合本身,原有的索引也会保留。
remove函数接受一个查询文档作为可选参数。删除数据时永久性的,不能撤销也不能恢复。
db.users.list.remove({“opt-out”:true})
更新文档
更新操作是原子的。如果两个更新同时发生,先到达服务器的先执行,最后到达服务器的最后执行。
两个参数,一个是查询文档,一个时修改器(modifier)文档
db.users.update(finddoc,modifier)
修改器
$inc
增加,键不存在时自动创建。只能用于数字类型的键
增加 db.users.update(_id,{“$inc”:{score:50}}) 增加50分
$set
指定一个键的值,如果这个键不存在则创建它
可以修改数据类型,也可以修改内嵌文档
1 | db.users.update({_id:ObjectId('asdasdasd')},{"$set":{"address":"test"}}) |
$unsert
删除键1
db.users.update(_id,{"$unsert":{"address":1}})
$push
数组修改器,向数组末尾加入一个元素,如果键不存在则创建一个数组1
db.users.update(_id,{"$push":{"address":{"city":"taiyuan","street":"as"}}})
$ne 使用在查询文档
如果一个值不在数组中就把它加进去1
db.papers.update({"autjprs cited":{"$ne":"Richie"}},{"$push":{"authors cited":"Richie"}})
$addToSet
1 | db.users.update(_id,{"$addToSet":{"emails":"test@t.com"}}) |
$each
一次添加多个邮件地址1
db.users.update(_id,{"$addToSet":{"emails":{"$each":["a@a.com",'a@b.com','a@c.com']}}})
$pop
移除一个元素1
2db.lists.update(_id,{"pop":{"emails":1}) //从末尾移除
db.lists.update(_id,{"pop":{"emails":-1}) //从头部移除
$pull
移除匹配条件的数组元素1
db.lists.update(_id,{"$pull":{"email":"a@a.com"}})
数组定位操作符$
通过位置活着定位操作符$1
2{"$inc":{"comments.0.votes":1}} //第一条评论的投票数+1
db.blog.update({"comments.author":"john",{"$set":{"comments.$.author":"jim"}}})
定位符只更新第一个匹配的元素。
upsert
如果没有找到符合条件的文档,则insert一个新的文档。如果找到,则更新该文档。1
db.analytics.update({"url":"/blog"},{"$inc":{"visits":1}},true)
第三个参数true表示该次update为upsert
save
文档存在时插入,存在时更新。
如果文档包括”_id”键,则会调用upsert,否则调用插入
更新多个文档,使用update的第四个参数
第4个参数true则更新所有文档,为false则只更新第一个符合条件的文档。默认为false1
db.users.update({birthday:"2014-01-01",{$set:{gift:"Happy birthday!"}}},false,true)
db.runCommand({getLastError:1})
1 | { |
findAndModify 命令
每个键对应如下:
- findAndModify 字符串,集合名
- query 查询文档,用来检索文档的条件
- sort 排序结果的条件
- update 修改器文档
- remove boolean,表示是否删除文档
- new 表示返回的事更新前的文档还是更新后的。默认是更新前的文档
- update和remove只能有一个,必须有一个
只能处理一个文档,不能直行upsert操作,只能更新已有文档。
插入、删除和更新都是瞬间完成的
查询
find(条件文档,指定返回的键)
findOne的参数和find一致
指定返回的键
{“username”:1,”email”:1,”address”:0} 表示返回username,email,_id,不返回address
条件文档
- $lt <
- $lte <=
- $gt >
- $gte >=
- $ne <>
- $or or
- $in in
- $nin not in
- $mod [a,b] 将查询的值除a,若余数等于b则返回该结果
- $not 元条件句,可用于任何其他条件之上。
- $exists 键是否存在 db.users.find({“address”:{“$exists”:true}})
- 正则表达式 db.users.find({“name”:/joe/i})
mongodb使用perl兼容的正则表达式(PCRE)库来匹配正则表达式
mongodb可以为前缀型正则表达式(比如/^joe/)查询创建索引,所以这类型的查询会非常高效。
1 | start = new Date("2014-01-01") |
查询数组
1 | db.food.insert({"fruit":["a","b","c"]}) |
可以将数组类型的键理解为:数组的每个元素都是整个键的值
$all 多个元素来匹配数组,查找包含$all参数的数组
也可以直接使用数组来精确匹配,精确匹配时会检查数组顺序
使用key.index语法指定下标来查询指定位置的元素
$size 查询长度,$size不能和其他查询子句组合
$slice 指定要返回的长度1
2
3
4db.blog.posts.find({},{"comments":{"$slice":10}}) //返回前10
db.blog.posts.find({},{"comments":{"$slice":-10}}) //返回后10
//返回后第24-33个元素,如果不够10个则返回23个元素后面的所有元素
db.blog.posts.find({},{"comments":{"$slice":[23,10]}})
第二个参数用了$slice后,将返回文档所有的键,除非特别声明不返回
查询内嵌文档
1 | db.people.find({"name.first":"joe","name.last":"Schmoe"}) |
$elemMatch 将限定条件进行分组,仅当需要对一个内嵌文档的多个键操作时才会用到
1 | db.blog.find({"comments":{"$elemMatch":{"author":"joe","score":{"$gte":5}}}) |
在博客中查找作者为joe并且评分大于5的评论
下面一个查询时错误的:1
db.blog.find({"comments.author":"joe","comments.score":{"$gte":5}})
这会直接返回这条blog
$where
1 | db.foo.find({"$where":function(){ |
如果函数返回true,则返回该文档。
1 | db.foo.find({"$where":"this.x + this.y==10"}) |
尽可能用索引作为前置过滤,然后使用$where对结果进行调优
游标
1 | var cursor = db.collection.find() |
hasNext() 检测有没有其他结果
next() 返回一条结果
forEach() 迭代游标中的结果
find方法总是会返回游标本身,只有要求获得结果时才发送查询,所以可以给游标附加额外的选项
1 | db.foo.find().sort({"x":1}).limit(1).skip(10) |
limit 指定返回结果的上限
skip 指定忽略结果的数量的上限
sort 排序,键值对,键对应文档的键名,值代表排序的方向,1为升序,-1为降序,可指定多个键值对。
1 | db.c.find().sort({username:1,age:-1}) |
对混合类型的键排序
如果一个键例如user_id为混合类型的,包括数字、字符串等,则按照以下顺序排序从小到大:
1.最小值
2.null
3.数字
4.字符串
5.对象/文档
6.数组
7.二进制数据
8.对象ID
9.布尔
10.日期
11.时间戳
12.正则表达式
13.最大值
分页
避免使用skip略过大量结果
可使用上一次查询的结果作为查询条件来获取下一页
随机选取文档
可以给文档增加一个额外的随机键”random”:Math.random()
然后根据random来查找
1 | random = Math.random() |
索引
1 | db.people.ensureIndex({"username":1}) |