码迷,mamicode.com
首页 > 数据库 > 详细

MongoDB 学习四 : 查询(续)

时间:2015-09-16 14:17:43      阅读:285      评论:0      收藏:0      [点我收藏+]

标签:

接着上章,继续介绍MongoDB的查询。

 

Querying on Embedded Documents

有两种方式查询嵌入式的子Documents:查询整个Document或者查询个别的键值对。

查询整个子Document和正常的查询是一样的。

我们有一个document:

{
     "name":{
           "first":"Joe",
           "last":"Schmoe"
           },
      "age":45
}

我们可以查找名为Joe Schmoe的人:

db.people.find({"name":{"first":"Joe","last":"Schmoe"}})

然而,查询一个子Document必须精确匹配。假如Joe决定添加一个中间名字段,那么上面这个查询就不成立了。

并且,这种查询类型同样是顺序敏感,{"last":"Schmoe","first":"Joe"},这样查询也是不匹配的。

通常针对子文档的key进行查找就不会出现上述的情况了:

db.people.find({"name.last":"Schmoe","name.first":"Joe"})

 

下来我们来看这条数据:

{
   "content":"...",
   "comments":[
         {
             "author":"joe",
             "score":3,
             "comment":"nice post" 
         },
         {
             "author":"mary",
             "score":6,
             "comment":"terrible post" 
         }
    ]
}

现在我们想要查找comments为joe并且得分大于5.

首先,我们不能这样查询

db.blog.find({"comments":{"author":"joe","score":{"$gte":5}}})

内嵌文档匹配要求整个文档完全匹配,而不是匹配comments这个key。

同样我们不能用

db.blog.find({"comments.author":"joe","comments.score":{"$gte":5}})

因为符合author条件的评论和符合score的评论可能不是同一条。也就是说会返回刚才显示的那个document。因为"author"在第一条评论中实现,"score"在第二条评论中实现。

正确的该如何呢?

db.blog.find({"comments":{"$elemMatch":{"author":"joe","score":{"$gte":5}}}})

 "$elemMatch"将限定条件进行分组,仅当需要一个内嵌文档的多个键操作时才会用到。

$where Queries

键值对是极富表现力的查询方式,但是有些查询他们也不能表达。

这时候,"$where"子句查询就出场了,它允许你在你的查询中执行任意的Javascript

最典型的应用就是比较文档中的两个键的值是否相等,例如有个条目列表,如果其中的两个值相等则返回文档。例:

db.foo.insert({"apple":1,"banana":6,"peach":3})
db.foo.insert({"apple":8,"spinach":4,"watermelon":4})

第二个文档中,"spinach"和"watermelon"的值相同,所以需要返回该文档。

db.foo.find({"$where":function(){
         for(var current in this){
              for(var other in this){
                    if(current !=other && this[current]==this[other]){
                               return ture;
                     }
              }
          }
          return false;
}})

如果函数返回为true,文档就作为结果的一部分被返回。

在非必要时,不要用"$where":它的查询速度比一般查询要慢很多。

 

Cursors

数据库使用游标来返回find的执行结果。客户端对游标的实现通常能够对最终结果进行有效的控制。

你可以限制结果的数量,略过部分结果,根据任意方向任意键的组合对结果进行各种排序,或者执行其他的一些功能强大的操作。

想从Shell中创建一个游标,首先要对集合填充一些文档,然后对其进行查询,并将结果分配给一个局部变量。这里,创建一个简单集合,而后做查询,并用cursor保存结果:

for(i=0;i<100;i++){
      db.collection.insert({x:i});
}
var cursor = db.collection.find()

这么做的好处是一次可以查看一条结果。如果将结果放在全局变量或者没有放在变量中,MongoDB Shell会自动迭代,自动显示最开始的若干文档。

也就是在这之前我们看到的种种例子,一般大家只想通过Shell看看集合里面有什么,而不是想在其中运行程序,这样的设计就很合适。

要迭代结果,可以使用游标的next方法。也可以使用hasNext来查看有没有其他的结果。典型的遍历如下:

while(cursor.hasNext()){
     obj = cursor.next();
     //do stuff
}

游标类还实现了迭代接口,所以可以在forEach循环中使用。

var cursor = db.people.find();
cursor.forEach(function(x){
      print(x.name)
})

当使用find的时候,shell并不立即查询数据库,而是等待真正开始要求获得结果的时候才发送查询,这样在执行之前可以给查询附加额外的选项。

几乎所有游标对象的方法都返回游标本身,这样就可以按任意顺序组成方法链。如下面几种是等价的:

var cursor = db.foo.find().sort({"x":1}).limit(1).skip(10);
var cursor = db.foo.find().limit(1).sort({"x":1}).skip(10);
var cursor = db.foo.find().skip(10).limit(1).sort({"x":1});

此时,查询还没有执行,所有这些函数都只是构造查询。假设我们执行

cursor.hasNext();

这时,查询发往服务器。shell立即获取钱100个结果或者前4M数据(两者之间较小者),这样下次调用next或者hasNext时就不必兴师动众跑到服务器上去了。

客户端用光了第一组结果,shell会再次连接数据库,并要求更多的结果。这个过程一直会持续到游标耗尽或者结果全部返回。

MongoDB 学习四 : 查询(续)

标签:

原文地址:http://www.cnblogs.com/showtime813/p/4810648.html

(1)
(1)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!