目录
摘要
Projections, ne, in, or, not,null,正则, all, slice(长度,范围),修改器与查询条件, elemMatch,游标,limit,sort,skip, ref
复杂查询
基本格式
db.<dbName>.find([cond,slice])
db.<dbName>.findOne([cond, slice])
find
表示查询所有结果findOne
表示查询第一条结果
Condition
find
或 findOne
的第一个参数表示条件,cond
为空或 {}
表示无条件查询。
查询的值必须是常量,不能是变量或者引用其它文档
Projections
find
或 findOne
的第二个参数表示过滤,其中 1
或 true
表示包含,0
或 false
表示排除。但是无论是否指定,除非指明需要进行排除,否则 _id
总是会被返回。
db.<dbName>.find(cond, slice)
db.<dbName>.findOne(cond, slice)
例如:
db.towns.find( {}, { name : 0 })
查询条件
概述
Mongo 中的条件操作符遵循字段格式:{ $op : value}
,其中 $op
是下列各种操作符。
ne, lt , gt, lte , $gte
db.test.find( {
"x" : { $ne : 3 }
} )
in, nin
db.towns.find(
{ famous_for : { $nin : ['food', 'beer']}}
)
$or
MongoDB 大部分查询条件都是隐含的 “与” 操作。
db.countries.find(
{
$or : [
{ _id : "mx" },
{ name : "United States"}
]
}
)
$not
可以用在任何条件之前
db.test.find( {
"x" : { $not : { $ne : 3 } }
} )
$exists
db.towns.find(
{ famous_for : { $exists : true }}
)
特定类型的查询
null
null
作为 value 可以匹配值为 null
或者不存在的文档
db.test.find( {
"createdAt" : null
} )
正则表达式
MongoDB 使用 Perl 表达式
/xxx/i
MongoDB 可以为前缀正则 /^xxx/
建立索引,所以这种查询会比较快。
例
db.towns.find( { name : /^New/ } )
日期
日期可以当做普通类型进行查询
var now = new Date()
db.test.find( {
"createdAt" : { $lt : now }
} )
数组中的查询
部分匹配
默认当字段为数组时,只要数组中有一个值匹配时就认为该记录被匹配到了。
db.towns.find({
"arr" : 10
})
或者使用 “$in” 部分匹配一组值
db.towns.find(
{ famous_for : { $in : ['food', 'hotdog']}}
)
$all
匹配全部指定的值
db.towns.find(
{ famous_for : { $all : ['food', 'beer']}}
)
$size
匹配拥有指定长度的数组
db.towns.find({
"arr" : { $size : 4 }
})
$slice
- 作为
find
的第二个参数。 - 选别数组的指定长度的子集合,正数从前开始取,负数从后开始取,也可以自己指定范围。
- 与其它操作符不同,未提及的键都会一并返回。
{ key : { "$slice" : size}}
{ key : { "$slice" : [from, to]}} //闭区间
指定长度,排除键 “name”
db.towns.find(
{ "arr" : 10 },
{ "arr" : { $slice : 4 }, "name" : 0 }
)
指定范围,返回所有键
db.towns.find(
{ "arr" : 10 },
{ "arr" : { $slice : [2, 3] } }
)
其它
- 修改器在文档外,查询条件在文档内
查询内嵌文档
- 要查询子文档,需要使用 “.” 分隔的嵌套字符串。
- 由于 “.” 在查询文档时表示深入内嵌文档,所以如果保存 url 等数据时应在插入之前先将 “.” 替换成其它不会混淆的特殊字符(如 url 的非法字符)
$elemMatch
匹配数组或内嵌文档中的所有字段
db.countries.find(
{
'exports.foods' : {
$elemMatch : {
name : 'bacon',
tasty : true
}
}
}
)
以上查询只有某个文档的 exports.foods
这个数组的某一条记录的 name 和 tasty 都同时满足条件才会返回。而如果使用通常查询,则只要某个文档的 exports.foods
里有一条记录满足 name 的条件,另一条记录满足 tasty 的条件则都返回。
$where
可以执行任意 Javascript 代码进行查询,效率比常规查询低很多
执行表达式
db.towns.find( { $where : "this.name == 'Shanghai'" } )
执行函数
db.towns.find(
{ $where : function(){
if (this.name == "Shanghai") return true;
else return false;
} }
)
函数返回 true 的结果会被作为文档返回
执行过程中每个 BSON 文档都会被转为 Javascript 对象,然后运行代码,此外也不能使用索引。
游标
游标用于控制 find
的结果
var cursor = db.yourDBName.find()
cursor.hasNext()
cursor.next()
游标还实现了 forEach 接口
cursor.forEach(function(d){
print(d.x);
});
游标的 find()
方法不会马上返回结果,所以可以加上各种限制条件。
此外大部分游标对象上的方法都会返回游标本身,因此可以完成链式操作。
var cursor = db.foo.find().sort({“x”:1}).limit(1).skip(1);
limit 和 skip 和 sort
sort
sort
中 1
表示升序,-1
表示降序,升序时不存在此键的数据会位于头部
db.towns.find().sort( { "name" : 1 } )
skip
skip
略过大量结果集时会很慢,应尽量避免
db.towns.find().skip(2)
不使用 skip 实现分页
- 利用
sort
再limit
限制第一页 - 之后根据前一次的最后一条记录加上之前的
sort
查询其余页
随机选取文档
低效做法是随机产生一个 “0” 到所有文档记录数量的数,然后 skip
掉之前的所有文档
好的做法是每次插入文档时加上一个随机字段,查询时产生一个随机数然后去 find
小于这个随机数的文档,这种情况下可以使用索引
引用
由于分布式的特点,连接操作时非常低效的。Mongo 通过引用来实现类似 “join” 的功能。
创建引用
格式为
{ $ref : "collection_name", $id : "reference_id"}
例
db.towns.update(
{ _id : ObjectId("55227ee3a78613d8b7786b62") },
{ $set : { country : { $ref : "countries", $id : "us" }}}
)
根据引用进行查找
方式一
var newyork = db.towns.findOne( { _id : ObjectId("55227ee3a78613d8b7786b62") });
db.countries.findOne( { _id : newyork.country.$id } )
方式二
db[ newyork.country.$ref ].findOne( { _id : newyork.country.$id })