MongoDB简单笔记三

原创
2011/07/30 17:24
阅读数 2.2K

用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);

 

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
5 收藏
0
分享
返回顶部
顶部