用findAndModify可以解决多线程争用问题,不知道这词用的对不对,反正自己明白就好了
用在update上
ps = db.runCommand({"findAndModify" : "processes",
"query" : {"status" : "READY"},
"sort" : {"priority" : -1},
"update" : {"$set" : {"status" : "RUNNING"}}).value
do_something(ps)
db.process.update({"_id" : ps._id}, {"$set" : {"status" : "DONE"}})
可以用在remove上
ps = db.runCommand({"findAndModify" : "processes",
"query" : {"status" : "READY"},
"sort" : {"priority" : -1},
"remove" : true).value
do_something(ps)
对于,这三种操作:insert,remove,update,这三种速度都很快,因为他们都是fire-and-forget类型的操作,即不用等待服务器作出response,就马上可以进行下一步操作。
那也许你就会问,我都不能确定服务器收到了我的数据,那怎么办,其实是有办法的,现在我还没有看到而已。
db.users.find({}, {"username" : 1, "email" : 1})
上面代码的意思是找到USERS里所有的数据里的username和email这两种KEY所对应的数据。
USERS里可能还有其它的key比如:gender,address什么的,但某些情况下我们只需要其中的一部分。
每次用find或是findOne的时候,它总是会返回_id这个key-value,不想让它返回这个怎么办,这样做
db.users.find({}, {"username" : 1, "_id" : 0}) #这时候就只会返回username了,不会返回_id了
"$lt", "$lte", "$gt", "$gte" 这四个分别代表 <, <=,>, >=,它们是用来设置查询范围的,比如
db.users.find({"age" : {"$gte" : 18, "$lte" : 30}}) #找出年龄在18<=age<=30之间的user
$ne在这里的用法,即是不等于的意思
db.users.find({"username" : {"$ne" : "joe"}}) #找出所有名字不是JOE的user
$in,后接个数组,表范围
db.raffle.find({"ticket_no" : {"$in" : [725, 542, 390]}}) #找出ticket_no为725或542或390的
数组里的数据类型可是不一样的
db.users.find({"user_id" : {"$in" : [12345, "joe"]}) #找出user_id等于12345或是joe的人
与$in相反的就是$uin,用法一样
db.raffle.find({"ticket_no" : {"$nin" : [725, 542, 390]}}) #找出ticket_no不是725,542,390的所有人
$or,$in或$uin的缺点就是只能用一个KEY作为条件,而是$or则可以多个
db.raffle.find({"$or" : [{"ticket_no" : 725}, {"winner" : true}]}) #两个条件满足其一即可
可以将$or和$in结合起来一起用
db.raffle.find({"$or" : [{"ticket_no" : {"$in" : [725, 542, 390]}},{"winner" : true}]})
$mod,如其名所表达的意思一样,求余数
db.users.find({"id_num" : {"$mod" : [5, 1]}}) #条件为id_num%5=1,满足条件的有1,6,11,16等
$not,取反运算
db.users.find({"id_num" : {"$not" : {"$mod" : [5, 1]}}}) #条件为id_num%5!=1.满足技术优势的有2,3,4,5,7等
$exists,用来确保KEY的存在
db.c.find({"z" : {"$in" : [null], "$exists" : true}}) #这样就不会返回例如{y:null}这样KEY不是Z的数据了
可以用正则作为value查询值
db.users.find({"name" : /joe/i})
db.users.find({"name" : /joey?/i})
$all,即满足所有条件
db.food.find({fruit : {$all : ["apple", "banana"]}}) #水果里必须同时有苹果和香蕉
$size
db.food.find({"fruit" : {"$size" : 3}}) #fruit的size必须是3
$slice
db.blog.posts.findOne(criteria, {"comments" : {"$slice" : 10}}) #前10条
db.blog.posts.findOne(criteria, {"comments" : {"$slice" : -10}}) #后10条
db.blog.posts.findOne(criteria, {"comments" : {"$slice" : [23, 10]}}) #以offset为23开始的10条
对于如下数据
{
"name" : {
"first" : "Joe",
"last" : "Schmoe"},
"age" : 45
}
可以这样来find,好处就是如果name里再加了个middle的属性,这条find还是有效的
db.people.find({"name.first" : "Joe", "name.last" : "Schmoe"}) #对document里的document操作
如果是这样的find就不行了
db.people.find({"name" : {"first" : "Joe", "last" : "Schmoe"}}) #如果更改了结构,加了个middle,就不能匹配
$elemMatch,用来匹配document里的document的,即embedded document,假设如下数据
{
"content" : "...",
"comments" : [
{
"author" : "joe",
"score" : 3,
"comment" : "nice post"
},
{
"author" : "mary",
"score" : 6,
"comment" : "terrible post"
}]
}
现在我们要找出作者是joe,score大于等于5的comment,就可以用$elemMatch
db.blog.find({"comments" : {"$elemMatch" : {"author" : "joe","score" : {"$gte" : 5}}}})
$where,用指定的javascript代码来做查询,先插入两条数据
db.foo.insert({"apple" : 1, "banana" : 6, "peach" : 3})
db.foo.insert({"apple" : 8, "spinach" : 4, "watermelon" : 4})
然后我们找出其中值相等的的数据,这里就是spinach和watermelon,因为它们的值都是4
db.foo.find({"$where" : function () {
for (var current in this) {
for (var other in this) {
if (current != other && this[current] == this[other]) {
return true;
}
}
}
return false;
}})
#如果函数返回真,则这条document就会被作为查询结果返回回来
#非特殊情况下还是不要用这种方式来查询,因为效率很低,因为每个document都会通过$where被转成BSON格式,
#交给javasript处理,然后再回到$where语句这里。
现在介绍下cursor,先插入100条数据,然后查询
for(i=0; i<100; i++) {
db.c.insert({x : i});
}
var cursor = db.collection.find()
然后你就可以这样来操作结果集了
while (cursor.hasNext()) { #hasNext用来判断还有没有数据
obj = cursor.next(); #next获得一条数据,然后当前的位置加1
do stuff #你要进行的操作
}
cursor同样也实现的迭代功能,即forEach
var cursor = db.people.find();
cursor.forEach(function(x) {
print(x.name);
});
组合用法,例如下面就是分页的一例子
var cursor = db.foo.find().sort({"x" : 1}).limit(1).skip(10); #sort,排序,1为升序,-1为降序
var cursor = db.foo.find().limit(1).sort({"x" : 1}).skip(10); #limit,限制返回数量
var cursor = db.foo.find().skip(10).limit(1).sort({"x" : 1}); #skip,偏移量
#以上只是建立好了查询语句,并没有真正向服务器提交查询,只有当调用了hasNext方法,查询才会被提交到服务器,
# 但是服务器并不回一次性将所有的查询结果一次返回,而是根据你调用next,hasNext方法
#每调用一次就返回一批数据,直到全部数据都返回
这里要说明下用skip来分页的方法效率很低,应该用其它给的办法代替,比如说先得到前100条数据,然后用第100条数据里的某一属性做为查询条件,得到剩下的数据,然后再limit(100)。代码如下
var page1 = db.foo.find().sort({"date" : -1}).limit(100)
var latest = null;
while (page1.hasNext()) {
latest = page1.next();
display(latest);
}
// 用第100数据里的date做为查询条件,得到剩下的数据
var page2 = db.foo.find({"date" : {"$gt" : latest.date}});
page2.sort({"date" : -1}).limit(100);