美文网首页我爱编程
MongoDB第四讲 深入MongoDB的查询操作

MongoDB第四讲 深入MongoDB的查询操作

作者: 孔浩 | 来源:发表于2017-11-29 21:06 被阅读0次

基础查询

MongoDB的查询操作非常重要,使用find和findOne进行查询,通过{}来设定查询条件,如果什么都不设置就是查询所有信息。

db.users.find() ##查询所有信息
db.users.findOne()##查询第一条记录

可以在find中使用逗号来分割多个查询条件,相当于关系数据库中的and操作

db.users.find({age:33})##查询年龄等于23的用户
> db.users.findOne({name:"foo",age:33})##查询名字为foo并且年龄为33的用户
{
        "_id" : ObjectId("5a1971ff15143821a5de24c7"),
        "name" : "foo",
        "age" : 33,
        "email" : "foo@example.com",
        "gender" : "male"
}

我们可以通过find的第二个条件来指定显示哪些key的信息

> db.users.findOne({name:"foo",age:33},{email:1,name:1})##仅仅显示email和name的信息
{
        "_id" : ObjectId("5a1971ff15143821a5de24c7"),
        "name" : "foo",
        "email" : "foo@example.com"
}

通过实例可以发现不管怎么设定都会显示_id,同样我们可以通过第二参数把key设置为0不显示信息

> db.users.findOne({name:"foo",age:33},{email:0})##排除email其他都显示
{
        "_id" : ObjectId("5a1971ff15143821a5de24c7"),
        "name" : "foo",
        "age" : 33,
        "gender" : "male"
}
>

通过下面的例子可以排除_id

> db.users.findOne({name:"foo",age:33},{_id:0,name:1})##仅仅显示name的信息
{ "name" : "foo" }
>

条件查询

MongoDB的查询同样可以像关系数据库一样加入>,<,=,!=的这些条件查询,只是使用的方式有些不一样而已

db.users.find({"age":{"$gte":20,"$lt":33}}).pretty() ##查询年龄大于等于20并且小于33的人
{
        "_id" : ObjectId("5a19740415143821a5de24c8"),
        "name" : "bar",
        "age" : 23,
        "email" : "bar@example.com",
        "gender" : "male"
}
{
        "_id" : ObjectId("5a19742115143821a5de24ca"),
        "name" : "world",
        "age" : 31,
        "email" : "world@example.com",
        "gender" : "male"
}

对于日期的处理也基本类似,使用new Date("yyyy-mm-dd")可以创建一个日期(详细日期:<YYYY-mm-ddTHH:MM:ss>),使用Date()可以插入当前日期。

##插入一条数据,日期是2017-12-22使用new Date()指定日期,使用Date()指定当前日期
> db.posts.insertOne({title:"first",content:".....",author:"foo",create:new Date("2017-12-22")})
> var d = new Date("2017-09-30")##创建一个日期对象
> db.posts.find({"create":{"$gt":d}}).pretty()##查询满足条件的日期对象
{
        "_id" : ObjectId("5a1977a815143821a5de24d3"),
        "title" : "first",
        "content" : ".....",
        "author" : "foo",
        "create" : ISODate("2017-12-22T00:00:00Z")
}

使用ne表示查询不等于某个的值

> db.users.find({name:{$ne:"foo"}},{name:1}).pretty()##查询name不等于foo的所有users
{ "_id" : ObjectId("5a19740415143821a5de24c8"), "name" : "bar" }
{ "_id" : ObjectId("5a19741115143821a5de24c9"), "name" : "hello" }
{ "_id" : ObjectId("5a19742115143821a5de24ca"), "name" : "world" }

使用逗号分割查询是以AND来进行条件的合并,如果要进行OR的查询,MongoDB提供了in和or两种方式,in表示查询的内容在某个范围内,in表示在某个范围内,而nin表示在不在范围内

db.users.find({name:{$in:["foo","bar"]}},{_id:0})##name在某个范围内
{ "name" : "foo", "age" : 33, "email" : "foo@example.com", "gender" : "male" }
{ "name" : "bar", "age" : 23, "email" : "bar@example.com", "gender" : "male" }
> db.users.find({name:{$nin:["foo","bar"]}},{_id:0})##name不在某个范围内
{ "name" : "hello", "age" : 25, "email" : "hello@example.com", "gender" : "male" }
{ "name" : "world", "age" : 31, "email" : "world@example.com", "gender" : "male" }

or的使用方式也类似,下例展示了如何查询AND和OR

> db.users.find( 
    {age:{$gt:22}, 
    $or:[{name:"foo"},{email:"hello@example.com"}] },
    {_id:0}
  )##查询,年龄大于22并且name为foo或者email为hello@example.com的所有users
{ "name" : "foo", "age" : 33, "email" : "foo@example.com", "gender" : "male" }
{ "name" : "hello", "age" : 25, "email" : "hello@example.com", "gender" : "male" }

特定类型的查询

首先看一下如何查询null的值,在MongoDB中null的值和关系数据库不太一样,关系数据库中,由于schema是固定的一般只会查询某个值为null,但是在MongoDB中可能存在没有这个Document的值,所以就会存在不同的需求。数据模型如下

> db.c.find()
{ "_id" : ObjectId("5a1b7bab29b9c4cdcc29a639"), "y" : 1 }
{ "_id" : ObjectId("5a1b7bad29b9c4cdcc29a63a"), "y" : 2 }
{ "_id" : ObjectId("5a1b7bb029b9c4cdcc29a63b"), "y" : null }
{ "_id" : ObjectId("5a1b7bb729b9c4cdcc29a63c"), "x" : 1 }
{ "_id" : ObjectId("5a1b7bb929b9c4cdcc29a63d"), "x" : 2 }

首先使用null来进行查询

> db.c.find({y:null})
{ "_id" : ObjectId("5a1b7bb029b9c4cdcc29a63b"), "y" : null }
{ "_id" : ObjectId("5a1b7bb729b9c4cdcc29a63c"), "x" : 1 }
{ "_id" : ObjectId("5a1b7bb929b9c4cdcc29a63d"), "x" : 2 }

我们发现查询出来的结果不仅仅包含了null值,还包含了不存在的值,此时如果希望查询是否包含需要使用exists来操作,需要强调的是exists是在查询的结果中过滤,所以并不是一个具体的条件,所以需要使用eq来配合。

db.c.find({y:{$eq:null,$exists:true}})##查询包含了y元素的并且y为null的
{ "_id" : ObjectId("5a1b7bb029b9c4cdcc29a63b"), "y" : null }
> db.c.find({y:{$eq:null,$exists:false}})##查询了不包含y元素的
{ "_id" : ObjectId("5a1b7bb729b9c4cdcc29a63c"), "x" : 1 }
{ "_id" : ObjectId("5a1b7bb929b9c4cdcc29a63d"), "x" : 2 }

MongoDB提供了正则表达式的查询,使用正则表达式可以组合出各种不同需求的查询,需要注意的是正则表达式的值使用/ 作为开始的和结束,如果要忽略大小写同样可以使用/i结尾,另外正则表达式的值不用加引号。

 db.users.find({name:/^f+/},{name:1,_id:0})##通过正则表达式匹配name是以f开头的
{ "name" : "foo" }
{ "name" : "fok" }

正则表达式和not配合起来就更加的好用

> db.users.find({name:{$not:/f+/}},{name:1,_id:0})##匹配不存在f的所有值
{ "name" : "bar" }
{ "name" : "hello" }
{ "name" : "world" }

数组查询

匹配数组非常简单

> db.food.find({fruit:"apple"})))##此时会匹配包含apple的数组
{ "_id" : ObjectId("5a1c2a6929b9c4cdcc29a640"), "fruit" : [ "apple", "banana", "orange" ] }
{ "_id" : ObjectId("5a1c2b4f29b9c4cdcc29a641"), "fruit" : [ "apple", "peach", "orange" ] }

db.food.find({fruit:"apple"}))) 这个会匹配所有包含了apple的数组,如果希望进行数组匹配使用all修饰符

>db.food.find({fruit:{$all:["apple","peach"]}},{_id:0})##匹配数组中包含有apple和peach的数据
{ "fruit" : [ "apple", "peach", "orange" ] }

以上匹配中apple和peach的顺序不会影响结果,通过下面的例子可以进行精确匹配,这个就连顺序也必须一样

db.food.find({fruit:["apple","peach","orange"]},{_id:0})##精确匹配,顺序要一致
{ "fruit" : [ "apple", "peach", "orange" ] }
> db.food.find({fruit:["apple","orange","peach"]},{_id:0})##顺序不一样无法找到数据

还可以指定位置来进行查询,如果要使用这种方式,需要注意的是key这个值必须加上"",下标是从0开始的

>db.food.find({"fruit.2":"orange"},{_id:0})##查询第三个元素是orange的数据
{ "fruit" : [ "apple", "banana", "orange" ] }
{ "fruit" : [ "apple", "peach", "orange" ] }

通过size可以查询数组长度等于某个值的数据,但是无法使用gt或者lt

> db.food.find({fruit:{$size:3}},{_id:0})##查询等于3的数据
{ "fruit" : [ "apple", "banana", "orange" ] }
{ "fruit" : [ "apple", "peach", "orange" ] }
> db.food.find({fruit:{$size:{$gte:3}}},{_id:0})##$size无法使用gt之类的条件
Error: error: {

如果希望做上面的操作,可以考虑插入一个size来保存,这个操作对性能的影响微乎其微,只是在插入数据的时候通过inc增加一条即可。对于find的第二个参数而言,如果时候数组可以通过slice来返回访问第几个元素

>db.food.find({fruit:"apple"},{fruit:{$slice:2},_id:0})##访问数组的前两个元素
{ "fruit" : [ "apple", "banana" ], "size" : 1 }
{ "fruit" : [ "apple", "peach" ] }
> db.food.find({fruit:"apple"},{fruit:{$slice:-2},_id:0})##访问后两个元素
{ "fruit" : [ "orange", "berry" ], "size" : 1 }
{ "fruit" : [ "peach", "orange" ] }
> db.food.find({fruit:"apple"},{fruit:{$slice:[2,3]},_id:0})##从第三个开始访问后三个元素
{ "fruit" : [ "orange", "berry" ], "size" : 1 }
{ "fruit" : [ "orange" ] }

下面将来演示几种内嵌文档的查询,首先看一下数据模型

> db.blog.findOne()
{
        "_id" : ObjectId("5a1c339b29b9c4cdcc29a642"),
        "title" : "first",
        "content" : "...",
        "author" : {
                "name" : "leon",
                "age" : 32
        },
        "comments" : [
                {
                        "content" : "c1",
                        "author" : "joe",
                        "score" : 4
                },
                {
                        "content" : "c2",
                        "author" : "jake",
                        "score" : 6
                }
        ]
}

要查询作者为leon的文档非常简单,通过.可以引导到关联对象中

> db.blog.find({"author.name":"leon"},{title:1,author:1,_id:0})
{ "title" : "first", "author" : { "name" : "leon", "age" : 32 } }

如果要查询
comments中作者为joe并且score大于等于5分的文章,这个需求如果按照常规的方式会把两条comments都查询出来,因为第二条comments的分数满足要求

> db.blog.find({"comments.author":"joe","comments.score":{$gte:5}},{title:1,author:1,_id:0})
{ "title" : "first", "author" : { "name" : "leon", "age" : 32 } }

这种情况需要使用elemMatch来解决

 db.blog.find({"comments":{$elemMatch:{"author":"joe","score":{$gte:5}}}})

最后,还有一种where查询,这种查询的效率稍微有些低,但是基本可以实现所有的查询,它的查询思路是将BSON转换为javascript对象来处理,还是首先看看数据模型

> db.point.find({},{_id:0})
{ "x" : 10, "y" : 30 }
{ "x" : 20, "y" : 20 }
{ "x" : 60, "y" : 60 }

如果希望查询x+y的值为40的数据,使用普通的方式就不太好查询,此时可以通过where来完成,使用where之后可以通过this来引用对象

 db.point.find(
... {$where:
... "function()
...  {
...     if(this.x+this.y==40) 
...         return true; 
...     else 
...         return false}
... "
... }) ##基于where的查询
{ "_id" : ObjectId("5a1c366429b9c4cdcc29a643"), "x" : 10, "y" : 30 }
{ "_id" : ObjectId("5a1c366b29b9c4cdcc29a644"), "x" : 20, "y" : 20 }

可以对上述的查询进行简单的转换,将function这些省略,只要写结果就行

> db.point.find({$where:"this.x+this.y==40"})
{ "_id" : ObjectId("5a1c366429b9c4cdcc29a643"), "x" : 10, "y" : 30 }
{ "_id" : ObjectId("5a1c366b29b9c4cdcc29a644"), "x" : 20, "y" : 20 }

最后再强调一下:where查询效率不高,一般非逼不得已不使用这个查询。

这一部分就讲这么多,通过这几部分的内容,基本对MongoDB有了一些基本的认识.

相关文章

  • MongoDB第四讲 深入MongoDB的查询操作

    基础查询 MongoDB的查询操作非常重要,使用find和findOne进行查询,通过{}来设定查询条件,如果什么...

  • MongoDB 常用查询操作

    MongoDB 查询操作可实现大部分关系型数据库的常用查询操作,本文对 MongoDB 常用查询进行讲解。 在阅读...

  • Spring boot MongoDB 复杂查询

    1.Mongodb查询多个对象 2.Mongodb查询单个对象 3.Mongodb分页查询 4.Mongodb统计...

  • Mongodb慢查询

    一、mongodb慢查询的作用: 二、mongodb开启慢查询的缺点: 三、mongodb开启查询慢查询: 四、m...

  • MongoDB查询条件-数组操作符 --- 2022-04-03

    本章节,介绍MongoDB关于JSON文档中的数组字段的匹配操作符。 MongoDB支持的数组查询条件 操作符说明...

  • 记录mongo中的一些特殊查询

    习惯用mysql的查询语句对mongodb复杂查询有时候力不从心,推荐mongodb聚合查询 该段mongodb的...

  • MongoDB积累

    一、mongodb通过工具连接 二、mongodb查询 1.mongodb数据库查询 一般查询:db.collec...

  • 2019-01-16

    MongoDB聚合操作 MongoDB版本:1.8.6.RELEASE需求:有一个会员消费记录表需要查询每个会员最...

  • MongoDB 数据类型查询 — $type使用

    MongoDB 使用过程中经常需要根据字段的类型来查询数据, 而MongoDB中查询字段类型是通过$type操作符...

  • MongoDB查询操作

    find()查询,在 MongoDB 中此方法接收的第二个可选参数是要检索的字段列表。 在MongoDB中,当执...

网友评论

    本文标题:MongoDB第四讲 深入MongoDB的查询操作

    本文链接:https://www.haomeiwen.com/subject/sinpbxtx.html