目录

 

MongoDB 查询操作

实例

简介 find() 以及投影操作

关系运算查询(大于、小于、等于...)

模糊查询

范围查询($in,$nin)

逻辑运算查询(或者 $or、等于 $and、非或者 $nor 以及 $not)

存在查询(存在 $exists、null 查询)

嵌套查询以及 "$all"、"$size"

取模查询($mod)

"$where" 查询


MongoDB 查询操作

MongoDB 查询文档使用 find() 方法。find() 方法以非结构化的方式来显示所有文档。

语法

MongoDB 查询数据的语法格式如下:

db.collection.find(query, projection)
  • query :可选,使用查询操作符指定查询条件
  • projection :可选,使用投影操作符指定返回的键。(通俗点讲就是:设置显示字段)

如果你需要以易读的方式来读取数据,可以使用 pretty() 方法,语法格式如下:

db.collection.find(query, projection).pretty()

实例

简介 find() 以及投影操作

最简单直接的方式:find() 查询

# 语法
db.collection.find()

# 示例
db.logs.find()

查询出指定条件的数据:

# 语法 
db.collection.find({"key" : "value"}) 

# 示例 
db.logs.find({"id" : "123456"})

隐藏掉不想显示的字段:projection 操作

不想显示的字段就设置为0,显示的字段设置为1(默认为显示,可以不用设置)

# 语法
db.collection.find({"key" : "value"}, {"key": 0 }})

# 示例 (不想显示 _id 字段)
db.logs.find({"id" : "123456"}, {"_id": 0 })

关系运算查询(大于、小于、等于...)

在 MongoDB 里面支持的关系查询操作:

             大于($gt)、小于($lt)、大于等于($gte)、小于等于($lte)、不等于($ne

示例一:查询性别为男的员工

db.emp.find({"sex":"男"}).pretty()

示例二:查询年龄大于 19 岁的员工

db.emp.find({"age": {"$gt":19}}).pretty()

示例三:查询年龄大于 19 岁的员工

db.emp.find({"age": {"$gt":19}}).pretty()

示例四:查询工资小于 6000 的员工

db.emp.find({"wages": {"$lt": 6000}}).pretty()

示例五:查询工资大等于 6000 的员工

db.emp.find({"wages": {"$gte": 6000}}).pretty()

示例六:查询年龄大于 19 岁的员工

db.emp.find({"age": {"$gt":19}}).pretty()

示例七:查询姓名不是 王五的员工

db.emp.find({"name": {"$ne": "王五" }}).pretty()

模糊查询

查询 title 包含"教"字的文档:

db.col.find({title:/教/})

查询 title 字段以"教"字开头的文档:

db.col.find({title:/^教/})

查询 title字段以"教"字结尾的文档:

db.col.find({title:/教$/})

范围查询($in$nin

    范围之中 $in, 不在范围之中 $nin

$in

    匹配键值等于指定数组中任意值的文档。类似于 SQL 中的 in 操作。

db.col.find({ field: { $in: [<value1>, <value2>, ... <valueN> ] } })

$nin

匹配键值不存在或者不等于指定数组中任意值的文档。类似于 SQL 中的 not in 操作。

db.col.find({ field: { $nin: [<value1>, <value2>, ... <valueN> ] } })

示例:查询姓名是 “张三”、“李四”、“王五” 的信息

db.emp.find( {"name": {"$in": ["张三", "李四", "王五" ] } } )

示例:查询姓名不是 “张三”、“李四”、“王五” 的信息

db.emp.find( {"name": {"$nin": ["张三", "李四", "王五" ] } } )

逻辑运算查询(或者 $or、等于 $and、非或者 $nor 以及 $not

$or

db.col.find( { $or: [      {key1: value1}, {key2:value2} ] } ).pretty()

示例:查询年龄大于 19岁, 或者工资大于 6000 的员工

db.emp.find( {"$or": [ {"age": {"$gt" : 19} }, {"wages": {"$gt": 6000 } } ] }).pretty()

$and

在进行逻辑运算的时候 “and” 操作是最容易,直接使用 “,”分割即可。

# 语法 db.col.find( { $and: [ { <expression1> }, { <expression2> } , ... , { <expressionN> } ] } )

示例一:查询 年龄在 19 ~ 25 之前的员工

db.emp.find({"age": {"$gte": 19, "$lte": 25 }})

示例二:查询 名字为 王五,工资大于 5000 的员工

  对于下面使用逗号分隔符的表达式列表,MongoDB会提供一个隐式的 $and 操作

//等同于{ $and: [ { "name": "王五" }, { "wages": { "$lt" :5000 } } ] }

db.emp.find({ "name": "王五" , "wages": { "$lt":5000 }} )

$nor

执行逻辑NOR运算,指定一个至少包含两个表达式的数组,选择出都不满足该数组中所有表达式的文档。

db.col.find( { $nor: [ { <expression1> }, { <expression2> }, ... { <expressionN> } ] } )

示例:查询 name 不为 “王麻子”,工资不小于 5000 的文档记录

db.emp.find( { "$nor": [ { "name" : "王麻子" }, { "wages": { "$lt": 5000 } } ] } )

$not

执行逻辑NOT运算,选择出不能匹配表达式的文档 ,包括没有指定键的文档。$not 操作符不能独立使用,必须跟其他操作一起使用(除 $regex)。

db.col.find( { field: { $not: { <operator-expression> } } } )

示例:查询 工资不大于 5000 (即工资小于等于 5000) 的文档数据

db.emp.find( { "wages": { "$not": { "$gt": 50 } } } ) //等同于db.emp.find( { "wages": { "$lte": 50 } } )

存在查询(存在 $existsnull 查询

$exists

如果 $exists 的值为true,选择存在该字段的文档;若值为 false 则选择不包含该字段的文档。

// 语法 
db.col.find( { field: { $exists: <boolean> } } )

示例:

// 查询不存在 wages 字段的文档(所有文档)
db.emp.find( { "wages": { "$exists" : false } })

// 查询 amount 字段存在,且值不等于 5000 和 6000 的文档
db.emp.find( { "wages": { "$exists" : true, $nin: [ 5000, 6000 ] } } 

如果该字段的值为 null,$exists 的值为 true 会返回该条文档,false 则不返回。

// 向集合中插入一条 wages 键值为 null 的文档
{"name":"test4","wages": null}

// 0条数据
db.inventory.find( { amount: { $exists: false } } )

// 所有的数据
db.inventory.find( { amount: { $exists: true } } )

由此可以看到:$exists 操作,仅仅只是判断 key 是否存在,而不去判断值是否为 null。

null 查询

如何检索出sex键值为null的文档,我们使用"in"、"where" 操作符,"$in" 判断键值是否为 null, "$exists" 判定集合中文档是否包含该键。

// 集合中有一条sex键值为null的文档
{"name":"xiaoming","age":20,"sex":"male"}
{"name":"xiaohong","age":22,"sex":"female"}
{"name":"lilei","age":24,"sex":null}

// 返回文档中存在sex键,且值为null的文档  
db.users.find({ "sex":{ "$in": [null], "$exists":true }})

// 返回文档中存在birthday键,且值为null的文档 
// 文档没有birthday键,所以结果为空
db.users.find({ "birthday" : { "$in": [null], "$exists" :true }})

另外一种查询方式:

db.users.find({ "sex" : null}) 
// 等同于 
db.users.find({ "sex" :{ "in" :[null], "exists" : true }})

嵌套查询以及 "$all"、"$size"

    嵌套查询:是指当我们的节点中存在子节点时,针对于子节点的查询操作

    $all 查询:匹配那些指定键的键值中包含数组。

    $size 查询:用其查询指定长度的数组。

 

嵌套查询

    查询文档有两种方式,一种是完全匹查询,另一种是针对 键/值对 查询。

// 我们的数据库中的数据
{ "name" : { "first" : "test1", "last" : "test2" } }

内嵌文档的完全匹配查询和数组的完全匹配查询一样,内嵌文档内键值对的数量,顺序都必须一致才会匹配:

> db.user.find({ name : { first : "test1", last : "test2" } });
{ "_id" : ObjectId("98d7b0d438962e1a2k7296d5"), "name" : { "first" : "test1", "last" : "test2" } }
>
//无任何返回值
> db.user.find({ name : {  last : "test2" , first : "test1"} });
>

 

推荐采用针对键/值对查询,通过点表示法来精确表示内嵌文档的键:

//查询结果一样
db.profile.find({  "name.first" : "test1" , "name.last" : "test2"});

//或者
db.profile.find({  "name.last" : "test2" , "name.first" : "test1"} );

 

"$all"

匹配那些指定键的键值中包含数组,而且该数组包含条件指定数组的所有元素的文档,数组中元素顺序不影响查询结果。

// 语法
db.col.find({ field: { $all: [ <value> , <value1> ... ] })

首先,我们先插入一点数据:

{"name":"t1", "amount":16, "tags":[ "school", "book", "bag", "headphone", "appliances" ]}
{"name":"t2", "amount":50, "tags":[ "appliances", "school", "book" ]}
{"name":"t3", "amount":58, "tags":[ "bag", "school", "book" ]}

查询出在集合inventory中 tags键值包含数组,且该数组中包含appliances、school、 book元素(必须要是全部包含)的所有文档:

db.inventory.find( { tags: { $all: [ "appliances", "school", "book" ] } } )

// 查出的结果
[ "school", "book", "bag", "headphone", "appliances" ]
[ "appliances", "school", "book" ]

文档中键值类型不是数组,也可以使用$all操作符进行查询操作,如下例所示 "$all" 对应的数组只有一个值,那么和直接匹配这个值效果是一样的。

//查询结果是相同的,匹配amount键值等于50的文档
db.inventory.find( { amount: {$all:[50]}} )

db.inventory.find( { amount: 50}} )

 

要是想查询数组指定位置的元素,则需使用key.index语法指定下标,例如下面查询出tags键值数组中第2个元素为"school"的文档:

db.inventory.find({"tags.1":"school"})

 

"$size"

用其查询指定长度的数组。

// 语法
db.col.find({field: {$size: value} })

查询集合中tags键值包含有3个元素的数组的所有文档:

db.inventory.find({ tags : { $size : 3 }})

// 查询的结果
{"name":"t2", "amount":50, "tags":[ "appliances", "school", "book" ]}
{"name":"t3", "amount":58, "tags":[ "bag", "school", "book" ]}

size必须制定一个定值,不能接受一个范围值,不能与其他查询子句组合(比如"gt")。但有时查询需求就是需要一个长度范围,这种情况创建一个计数器字段,当你增加元素的同时增加计数器字段值。

//每一次向指定数组添加元素的时候,"count"键值增加1(充当计数功能)
db.collection.update({ $push : {field: value}, $inc :{count : 1}})

//比较count键值实现范围查询
db.collection.find({count : {$gt:2}})

取模查询($mod

 

匹配字段值对(divisor)取模,值等于(remainder)的文档。

// 语法
db.col.find({ field: { $mod: [ divisor, remainder ]} })

// 通俗的理解为:
{ field: { $mod: [ 数字, 小数位 ]} }

 

示例:查询集合中 amount 键值为 4 的 0 次模数的所有文档,例如 amount 值等于 16 的文档

db.inventory.find( { amount: { $mod: [ 4, 0 ] } } )

//  查询结果
{"name":"t1", "amount":16, "tags":[ "school", "book", "bag", "headphone", "appliances" ]}

 

正则查询($regex

操作符查询中可以对字符串的执行正则匹配。 MongoDB使用Perl兼容的正则表达式(PCRE)库来匹配正则表达式.

# 语法
## 基础语法
{key: 正则标记}

## 完整语法
{key: {"$regex": 正则标记, "$options": 选项}}

​

对于 options 主要是设置正则的信息查询的标记:

  • "i": 忽略字母大小写
  • "m": 忽多行查找
  • "x": 空白字符串除了被转义的或在字符类中意外的完全被忽略
  • "s":匹配所有的字符(圆点,“.”),包括换行内容# 语法 ## 基础语法 {key: 正则标记} ## 完整语法 {key: {"$regex": 正则标记, "$options": 选项}}

 

如果是直接使用(javaScript)那么只能够使用 "i" 与 "m",而 "x" 和 "s" 必须使用 "$regex"。

//查询name键值以“4”结尾的文档
db.inventory.find( { name: /.4/i } );
db.inventory.find( { name: { $regex: '.4', $options: 'i' } } );

"$where" 查询

操作符功能强大而且灵活,他可以使用任意的JavaScript作为查询的一部分,包含JavaScript表达式的字符串或者JavaScript函数。

新建fruit集合并插入如下文档:

//插入两条数据
db.fruit.insert({"apple":1, "banana": 4, "peach" : 4})
db.fruit.insert({"apple":3, "banana": 3, "peach" : 4})

 

比较文档中的两个键的值是否相等.例如查找出banana等于peach键值的文档(4种方法):

//JavaScrip字符串形式
db.fruit.find( { $where: "this.banana == this.peach" } )
db.fruit.find( { $where: "obj.banana == obj.peach" } )

//JavaScript函数形式
db.fruit.find( { $where: function() { return (this.banana == this.peach) } } )
db.fruit.find( { $where: function() { return obj.banana == obj.peach; } } )

查出文档中存在的两个键的值相同的文档,JavaScript函数会遍历集合中的文档:

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

 

注意:我们尽量避免使用"Where"査询,因为它们在速度上要比常规査询慢很多。每个文档都要从BSON转换成JavaScript对象,然后通过"where"的表达式来运行;同样还不能利用索引。

 

附:

更多操作查看官网链接:https://docs.mongodb.com/manual/reference/operator/query/

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐