mongodb的查询
MongoDB中使用find进行查询 查询就是返回一个集合中文档的子集 子集合的范围从0到整个集合 find的第一个参数决定了要返回那些文档 这个参数是一个文档 用于指定查询条件 空的查询文档会匹配集合的全部内容 db.c.find() 查询集合c 中的全部文档
find({"age":27}) {"username":"joe"} {"username":"joe","age":27}
指定需要返回的键
find({},{"username":1,"email":1})
不需要返回的键 ({"_id":0})
查询条件 $lt < $lte <= $gt > $glt >= 使用方法
{"age":{"$gte":18,"$lte":30}} 查询年龄在18到30之间的 含18 30
找 2007年1月1日 之前注册的
var start = new Date("01/01/2007")
find({"register":{"$lt":start}})
不相等 #ne 查询名字不为joe的人 find({"username":{"$ne":"joe"}})
OR查询
mongoDB中有两种OR查询 $in用于查询一个键多个值 $or更通用一些 可以在多个键中查询任意给定的值
find({"ticket_no":{"$in":[75,56,23]}}) 查询 中奖号码是 75 57和23 的人
$in可以指定不同类型的条件和值
find({"user_id":{"$in":[1234,"joe"]}})
这回匹配user_id等1234的 也会匹配user_id等于 "joe"的
和$in相对的是$nin 用法和$in一样
$or 查询
find({"$or":[{"ticket_no ":725},{"winner":true}]}) 查询中奖号码为725或者 winner等于true
$or和$in 组合使用
find({"$or":[{"ticket_no":{"$in":[725,542,390]}},{"winner"true}]})
使用or查询是时候 第一个条件尽可能匹配更多的文档去 这样才高效
$not 是元条件句 可以用在任何其他条件上 就拿去模运算符来说$mod
find({"id_num":{"$mod":[5,1]}}) 查询除以五 余数是1 的 匹配的有1 6 11 16 如果想返回id_num为 2 3 4 5 7 8 9 10 12
find({"id_num":{"$not":{"$mod":[5,1]}}})
特定类型的查询
null find({"y":null}) 不进匹配y的值是null的文档 也会匹配不包含这个键的文档
想要做区分 就需要$exists 来设定
find({"z":{"$in":[null],"$exists":true}}) 匹配z的值为null 键存在的文档 很遗憾mongoDb没有$eq这个操作符 所以这个条件查询看上去令人费解 但是使用只有一元素的$in操作符 效果是一样的
正则表达式
find({"name"/joe/i}) 匹配区分大小的joe 他可以匹配自身 如果你把正则表达式存入数据库中的话
查询数查询数组元素 和 查询标量值一样的 例如查询水果 数据 {"fruit":["apple","banana","peach"]}
就可以这样查询 find({"fruit":"apple"}) 就可以匹配到这个文档 这个查询好比我们对一个这样的(不合法)文档进行查询 {"fruit":"apple","fruit":"banana","fruit":"peach"} 所以不推荐使用
$all
如果需要多个元素来匹配数组 就需要$all
{"fruit":["apple","banana","peach"]}
{"fruit":["apple","kumquat","orange"]}
{"fruit":["cherry","banana","apple"]}
要找到即含有apple 的又有banana 的 find({"fruit":{$all:["apple","banana"]}}) 这里顺序无关紧要
也可以读数组进行精确的匹配 基于位置 key.index 下标从0开始
find({"fruit.2","peach"})
$size
可以用来查询特定长度的数组
find("fruit":{"$size":3}) 查询长度为3的数组
$slice 操作符
find的第二个参数 是可选的 可以用来指定需要返回的键 这个特别的$slice 操作符可以返回某个键匹配的数组元素的一个子集
find(criteria,{"commts":{"$slice":10}}) 返回查询的前10条评论 也可以是后10条 -10
也可以指定偏移值以及希望返回的数量 [23,10] 意思是 返回24-34个 如果数组不够 10个返回全部
除非特别说明 否则 使用$slice时 将返回文档中所有键 别的键说明符都是默认不返回未提及建的 这点与$slice 不大一样
查询内嵌文档
两种方法 查询整个文档 和 针对键值查询
{
"name" : {
"first" : "joe"
"last" : "Schmoe"
},
"age" : 45
}
查询 姓名 joe Schmoe 可以这样查询
find({
"name" : {
"first" : "joe"
"last" : "Schmoe"
}
})
但是 如果要查询一个完整的子文档 那么子文档必须精确匹配 如果joe 要加一个中间名 这个查询就不能用了 而且这么查询还是和顺序相关的 如果first 和last 交换位置 什么也匹配补刀
如果允许的话 通常针对内嵌文档的查询 都是针对键值进行查询的 这是比较好的做法
find({"name.first":"joe","name.last":"Schmoe"})
这样查询 即使数据模式改了 也不会导致所有的查询因为要精准匹配而一下都挂掉
当文档的结构变得复杂以后 文档的查询需要一些技巧 例如 假设有博客文章若干 要找到有joe法比安哦的5分以上的评论 博客的文章的结构 :
{
"content" : "sfesfe",
"comments" : [
{
"author" : "joe",
"score" : 3,
""comment : "nice post"
},{
"author" : "mary",
"score" : 6,
""comment : "terrible past"
}
]
}
"content" : "sfesfe",
"comments" : [
{
"author" : "joe",
"score" : 3,
""comment : "nice post"
},{
"author" : "mary",
"score" : 6,
""comment : "terrible past"
}
]
}
不能直接用 find({"comments":{"author":"joe","score":{"$gte":5}}})来查询 内嵌文档的匹配 必须要整个文档完全匹配 而这个查询 不会匹配"comment"建 使用 find({"comments.author":"joe","comments.score":{"$glt":5}}) 也不行 因为符合作者是joe 的评论和符合score条件的评论 可能不在一条 也就是说 会反悔刚才显示的那个文档 作者在第一条匹配了 分数在在第二条匹配了
要正确的指定一组条件 而不必指定每个建 就需要使用$elemMatch 这种模糊命令的条件句能用来在查询条件中部分指定匹配数组中的单个内嵌文档 find({"comments":{"$elemMatch":{"author":"joe","score
":{"$gte":5}}}})
$elemMatch将限定条件进行分组 仅当需要对一个内嵌文档的多个键操作时才有用
游标
其客户端对游标的实现通常能够对最终结果进行有效的控制 可以限定数量 略过部分结果 根据任意顺序的组合对结果进行各种排序 或者执行其他强大的操作
要想砸shell中创建一个游标 查询出目标数据 并且将查询结果分配给一个局部变量
var cursor = db.foo.find()
查看游标结果 有两种法子 :
while (cursor.hasNext()) {
obj = cursor.next()
}
cursor.forEach(function(index) {
print(index.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().sort({"x":1}).skip(10).limit(1)
这些返回的结果都是一样的
知道执行 cursor.hasNext() 这是查询被发往服务器 shell立刻获得前100个结果 或者前4m数据 这样下次调用next或者hasNext时 就不必在连接数据库了 如果数据用了 shell 会再次联系数据库 使用getMore去请求提取更多的结果 如果有 返回下一批结果 这个过程会一直持续到游标耗尽或者结果全部返回
limit skip sort
限制返回结果的数量 忽略一定数量的结果以及排序
find().limit(2) 返回3个结果
find().skip(3) 忽略前三个文档
sort 排序 指定一个或者多个字段排序 1升序 -1降序
find().sort({"username":1,"age":-1})
想搜索MP3 每页50个 按照价格从高到低排序
find({"desc":"MP3"}).limit(50).sort({"price":-1})
点击下一页
find({"desc":"MP3"}).limit(50).skip(50).sort({"price":-1})
这样看起来很美好的分页就完成了
但是 忽略过多的结果 会导致性能问题
如何避免呢 不用skip进行分页
var page1 = db.foo.find().sort({"date":-1}).limit(100)
var latest = null;
while(page1.hasNext()) {
latest = page1.next()
display(latest)
}
var page2 = db.foo.find("date":{"$gt":latest.date});
page2.sort({date:-1}).limit(100)
这样查询中没有skip 也实现了分页