Step into MongoDB - 07 - 复杂查询

目录

摘要

Projections, ne in, or not,null,正则, all slice(长度,范围),修改器与查询条件, elemMatchlimitsortskip ref

复杂查询

基本格式
db.<dbName>.find([cond,slice])
db.<dbName>.findOne([cond, slice])
  • find 表示查询所有结果
  • findOne 表示查询第一条结果
Condition

findfindOne 的第一个参数表示条件,cond 为空或 {} 表示无条件查询。

查询的值必须是常量,不能是变量或者引用其它文档

Projections

findfindOne 的第二个参数表示过滤,其中 1true 表示包含,0false 表示排除。但是无论是否指定,除非指明需要进行排除,否则 _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

sort1 表示升序,-1 表示降序,升序时不存在此键的数据会位于头部

db.towns.find().sort( { "name" : 1 } )
skip

skip 略过大量结果集时会很慢,应尽量避免

db.towns.find().skip(2)
不使用 skip 实现分页
  1. 利用 sortlimit 限制第一页
  2. 之后根据前一次的最后一条记录加上之前的 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 })
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值