Mongodb 查询 (2)2011-12-12 10:52Mongodb 查询
查询嵌入的document
查询嵌入的整个document和普通的查询没有差别,比如我们有这样一个document
{
"name" : {
"first" : "Joe",
"last" : "Schmoe"
},
"age" : 45
}
那么我们就可以这样查询名字叫Joe Schmoe的人
> db.people.find({"name" : {"first" : "Joe", "last" : "Schmoe"}})
如果Joe要加一个middle name,这个查询就不行了,这种查询必须匹配整个嵌入的document,而且key是有顺序的。
我们可以用.来直接查询嵌入的key。
> db.people.find({"name.first" : "Joe", "name.last" : "Schmoe"})
点号在查询用document里就被解释为“通向嵌入的document”,所以document的key里边不能包含点号。
$where 查询
$where子句允许你在查询里执行arbitary javascript,使你几乎可以在查询中做任何事情。
最常见的例子就是比较document里边两个key的值。举个例子,我们有个list,我们想返回里边的key的值里有相等的document
(随便哪两个key,只要它们的value相等即可)。
> db.foo.insert({"apple" : 1, "banana" : 6, "peach" : 3})
> db.foo.insert({"apple" : 8, "spinach" : 4, "watermelon" : 4})
第二个document里,菠菜和西瓜的值是相等的,这个应该返回,这个使用$条件查询符号是做不到的。
> 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;
... }});
如果函数返回true,那么这个document就会作为结果集的一部分被返回。
刚才我们定义了一个函数,给$where查询指定一个字符串是一样的效果
> db.foo.find({"$where" : "this.x + this.y == 10"})
> db.foo.find({"$where" : "function() { return this.x + this.y == 10; }"})
这两个查询是等价的。
如非必要,尽量不要使用$where查询,$where查询比一般的查询慢很多,每个document都必须从BSON转换为一个javascript对象,
然后执行$where表达式。而且,索引也不能使用。你可以通过组合使用$where查询和非$where查询来降低使用它的代价。
4.游标
find方法使用游标返回查询结果,游标的客户端实现使你可以对最终结果做很多的控制。在shell里创建一个游标很简单,往collection里放些document,
执行查询,将返回结果指派给一个本地变量即可。
> for(i=0; i<100; i++) {
... db.c.insert({x : i});
... }
> var cursor = db.collection.find();
你可以使用next方法来遍历结果,使用hasNext方法来检查有没有下一个,典型的循环如下
> while (cursor.hasNext()) {
... obj = cursor.next();
... // do stuff
... }
cursor类同样实现了iterator接口,所以你可以使用forEach循环
> var cursor = db.people.find();
> cursor.forEach(function(x) {
... print(x.name);
... });
adam
matt
zak
当你调用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});
在这个时候查询并未执行,所有的函数都只是构建查询。现在我们调用hasNext方法,
> cursor.hasNext()
这时候查询被送到服务器,shell就立刻取到了前100条结果或者前4MB的结果,所以接下来在调用next方法的时候就不会再发送请求
以及接受结果,当第一次返回的结果集用完的时候,shell会再次联系服务器,请求更多的结果。
Limits, Skips, 和Sorts
limit函数限制返回的结果集的上限,如,只返回3个结果
> db.c.find().limit(3)
skip函数跳过前x个结果,返回剩余的
> db.c.find().skip(3)
sort方法使用一组键值对做参数,key是document里的key的名字,value是1升序或者-1降序。
如,按名字升序和年龄降序排序
> db.c.find().sort({username : 1, age : -1})
比较顺序
mongoDB有一个关于各种数据类型之间比较的等级制度。在某些情况下,你可能有一个key,它的值有多种类型,如果你想按照该
key排序,mongoDB有一个预定义好的顺序,它们从小到大分别为:
1. Minimum value
2. null
3. Numbers (integers, longs, doubles)
4. Strings
5. Object/document
6. Array
7. Binary data
8. Object ID
9. Boolean
10. Date
11. Timestamp
12. Regular expression
13. Maximum value
获取一致性的结果
处理数据的常见方式就是从mongoDB里取出来,然后修改它,再存储进mongoDB,如下:
cursor = db.foo.find();
while (cursor.hasNext()) {
var doc = cursor.next();
doc = process(doc);
db.foo.save(doc);
}
结果集数量很小的时候,这样子做是没问题的,如果结果集很大,这个做法就行不通了。
想象一下document是如何存储的,你可以像下图4-1一样来理解存储document的collection,每个雪花代表一个document,因为
它们和document一样,都很漂亮而且独一无二。
图4-1
现在,我们执行一个find,它从头开始向右返回结果。程序获取前100个document并处理它们,然后将它们存储回数据库,如果一个
document没有足够的空间来容纳新的document,如图4-2,那么就需要给它重新指定存储位置。通常,这个新的document 会重新
定位到collection的尾部,如图4-3.
图4-2
图4-3
现在,我们的程序持续不断地批量获取document,当它到达collect尾部的时候,那些被重新定位的document会再次返回,如图4-4.
图4-4
这个问题的解决办法是,对查询使用snapshot,如果添加了“$snapshot"选项,查询就会按照collection未被改变的视图运行。
本文来自: Prosurfer的博客
http://hi.baidu.com/prosurfer/blog/item/e8ee5e2ce1e4b6f28a1399f3.html