一、getLastError 查看更新结果
- 可以使用getLastError命令的getLastOpStatus来查看更新结果
db.runCommand({getLastError:1});
{
"err":null,
"updateExisiting":true, //是否进行了更新
"n":2, //更新的文档数
"ok":true
}
二、 findAndModify 更新文档并返回更新后的文档
- 返回更新后的文档要求等待数据库响应,所以会比普通的update操作慢一些
- 问题的引入:有一个保存了处理流程的集合processes,需要从中间取出process,并更新其状态为 Ready,Running,Done。并且是多线程操作
ps=db.processes.find({"status":"Ready"}).sort({"priority":-1}).limit(1).next();
db.processes.update({"_id":ps._id},{"$set":{"status":"Running"}});
do_process(ps);
db.processes.update({"_id":ps._id},{"$set":{"status":"Done"}});
- 以上方法在执行的时候会产生资源竞争,当多个线程在获取流程信息并执行时,可能会出现一个线程已经获取了文档,还未修改状态,但是另一个线程也获取到了同一个文档,这样一个流程就被执行了两遍。
var cursor=db.processes.find({"status":"Ready"}).sort({"priority":-1}).limit(1);
while( (ps=cursor.next() )!= null ){
...ps.update({"_id":ps._id,"status":"Ready"},{"$set":{"status":"Running"}});
...var lastOp=db.runCommand({getlasterror:1});
...if(lastOp.n==1){
...do_process(ps);
...db.processes.update({"_id":ps._id},{"$set":{"status":"Done"}})
...break;
...}
...cursor=db.processes.find({"status":"Ready"}).sort({"priority":-1}).limit(1);
...}
- 以上方式可实现在执行update的同时,检查status是否还在Ready状态来避免线程冲突,但是可能会造成一个线程一直跟随另一个线程检查文档状态的情况,导致一个线程的资源被浪费。以下采用了findAndModif命令来在同一个操作里返回文档并更新它
ps=db.runCommand({"findAndModify":"processes",
..."query":{"status":"Ready"},
..."sort":{"priority":-1},
..."update":{"$set":{"status":"Running"}}.value,
..});
do_process(ps);
ps.update({"status":"Ready"},{"$set":{"status":"Done"}});
- findAndModify命令的参数key为:
findAndModify: string, 集合名称
query:对象,检索条件
sort: 对象,排序方式
update: string, 更新搜索到的文档的方式
remove: boolean,指示是否删除查询到的文档
new: boolean, 指示返回的文档是更新前的还是更新后的,默认为更新前的.
- update 和remove有且只能有一个,如果query参数匹配不到文档,此命令会报错。
- findAndModify命令执行耗时相当于一次查询+一次更新+一次getLastError顺序执行的时间
三、distinct 找出给定键的不同值
- 使用时,必须指定集合和键
db.runCommand({"distinct":"collection","key":"keyName"});
四、group 分组查询命令
- 使用命令进行分组查询
db.runCommand({group:{
ns:'collection',//集合名称
$keyf:function(doc){return key:doc.age},//分组依据的键名
initial:{num:0},//分组累加器初始值
$reduce:function(doc,prev){prev.num++},//分组累加器,第一个默认参数为当前文档,第二个参数为分组累加器的前一个文档
finalize:function(doc){doc.count=doc.num; delete doc.num;}//完成器,每个文档遍历完成后执行
}})
本文介绍了几个常用的mongodb的命令