• (5) MongoDB查询操作


    mongodb采用find来进行查询操作,根据传进去的参数不同,可以进行不同类型的操作。

    1. 最简单的查询

    首先,最简单的查询,当然是不带任何条件的查询,这在我们前面的例子中也看过了,如db.blog.find(),该查询将返回blog集合中所有的文档。

    2. 限定条件

    在关系型数据库(RDB)中,我们通过where来限定查询条件,如:

    select *

    from user

    where age =28

    我们来看看在mongodb中如何进行类似的操作:

    db.user.find({"age":28})

    mongodb的第一个参数用来指定要返回哪些文档,如,上面的例子表示,返回user集合中,age为28的所有文档。

    在RDB中,我们通过where A and B来指定多个条件,mongodb中的and也很简单,只需在第一个参数中列出多个键即可,如:

    db.user.find({"age":28,"name":"tian"})

    3. 返回指定的键

    在RDB中,我们可以通过指定列来我们需要的字段,在mongodb中,我们可以通过为find指定第二个参数,来指定我们需要返回的键。

    返回所有的字段有时是不必要的,甚至要浪费数据的传输量和客户端的解码时间。

    如:

    > db.user.insert({"_id":1,"name":"tian","age":28})
    > db.user.insert({"_id":2,"name":"jerry","age":36})
    > db.user.insert({"_id":3,"name":"harry","age":26})
    > db.user.find({},{"name":1})
    { "_id" : 1, "name" : "tian" }
    { "_id" : 2, "name" : "jerry" }
    { "_id" : 3, "name" : "harry" }

    我们发现,age这个键没有返回,但是_id这个键返回了,这是mongodb默认的。

    Note:在上面的find语句中,第一个参数为{},表示没有限定条件。

    有时候,集合里面的键比较多,如果我们一一列举显得有点罗嗦,这个时候,我们可以通过指定不需要返回的键,如:

    > db.user.find({},{"age":0})
    { "_id" : 1, "name" : "tian" }
    { "_id" : 2, "name" : "jerry" }
    { "_id" : 3, "name" : "harry" }

    将不需要的键指定为0,这样当集合的键比较多时,就可以省掉不少麻烦了。

    4. 其他查询条件

    除了前面一些简单的匹配外,mongodb还可以进行更加复杂的查询,我们通过跟RDB对比进行说明

    image

    跟RDB对比后,mongodb的用法就一目了然了。虽然mongodb的操作符没有像平常的比较运算符好记,但是mongodb的这些操作符也都是根据英文缩写,如$gt就是great than,$lte就是less than,所以也不算难记。

    5. 特殊的null

    null无论在哪里,都注定是特殊的一员,mongodb中的null也是一样。

    首先,null确实可以匹配自身,如:

    > db.user.insert({"_id":4,"name":"leon",age:null})

    > db.user.find({"age":null})
    { "_id" : 4, "name" : "leon", "age" : null }

    但是,null还会匹配不存在的键

    > db.user.insert({"_id":6,"name":"jim"})
    > db.user.find({"age":null})
    { "_id" : 4, "name" : "leon", "age" : null }
    { "_id" : 6, "name" : "jim" }

    我们看到,没有age这个键的文档也匹配上了。

    当然,我们也可以防止这种情况发生,那就是指定存在null值的键的文档才返回:

    > db.user.find({"age":{"$in":[null],"$exists":true}})
    { "_id" : 4, "name" : "leon", "age" : null }

    这个写法看上去很别扭,但是,没办法,mongodb没有提供类似$eq(equal)的操作符。

    6. 操作数组

    先看个简单的例子:

    > db.food.insert({"fruit":["apple","banana","peach"]})
    > db.food.find({"fruit":"apple"})
    { "_id" : ObjectId("500fe140ad99f95967489682"), "fruit" : [ "apple", "banana", "peach" ] }

    只要数组里面包含要匹配的值,就会匹配成功。

    有时候,我们需要查找数组中包含多个值的,就需要用到$all了。

    考虑这样一个集合

    { "_id" : ObjectId("500fe140ad99f95967489682"), "fruit" : [ "apple", "banana", "peach" ] }
    { "_id" : ObjectId("500fe349ad99f95967489683"), "fruit" : [ "cherry", "banana","apple" ] }
    { "_id" : ObjectId("500fe358ad99f95967489684"), "fruit" : [ "apple", "orange", "peach" ] }

    我们要找到既包含apple,又包含banana的文档:

    > db.food.find({"fruit":{"$all":["apple","banana"]}})
    { "_id" : ObjectId("500fe140ad99f95967489682"), "fruit" : [ "apple", "banana", "peach" ] }
    { "_id" : ObjectId("500fe349ad99f95967489683"), "fruit" : [ "cherry", "banana","apple" ] }

    我们还可以通过数组进行查找,需要注意的是,用数组查找就是完全匹配了,如:

    > db.food.find({"fruit":["apple","banana"]})
    > db.food.find({"fruit":["apple","banana","peach"]})
    { "_id" : ObjectId("500fe140ad99f95967489682"), "fruit" : [ "apple", "banana", "peach" ] }

    有时候需要根据数组个数来查找的,如

    > db.food.find({"fruit":{"$size":3}})

    RDB中经常用top来获取前几条数据,对于数组的前几个的获取,就需要用到$slice了,如:

    > db.food.find({},{"fruit":{"$slice":2}})
    { "_id" : ObjectId("500fe140ad99f95967489682"), "fruit" : [ "apple", "banana" ]}
    { "_id" : ObjectId("500fe349ad99f95967489683"), "fruit" : [ "cherry", "banana" ] }
    { "_id" : ObjectId("500fe358ad99f95967489684"), "fruit" : [ "apple", "orange" ]}

    可以看到,fruit中只返回了前两个值。

    也可以返回指定的返回的元素,如

    > db.food.find({},{"fruit":{"$slice":[2,4]}})

    这个语句是指,跳过前面的2个元素,返回3~4这2个元素。

    7.内嵌文档的查询

    所谓内嵌文档,就是指文档的值本身又是一个文档。

    假设有这样的一个文档:

    {

        "name”:

                    {

                      "first":"terry",

                       "last":"chen"

                     },

         "age":12

    }

    要寻找名字为terry chen的可以这样:

    > db.userinfo.find({"name":{"first":"terry","last":"chen"}})
    { "_id" : ObjectId("500fee69ad99f95967489687"), "name" : { "first" : "terry", "last" : "chen" }, "age" : 12 }

    但是有个问题就是如果我们把"first"键和"last"键位置放错了,或者我们在加入一个"middle"键,那么就没有办法找到该文档了。

    这就需要我们更改查询的策略,mongodb中用点表示查询内嵌的键:

    > db.userinfo.find({"name.first":"terry","name.last":"chen"})

    这样,即使将来加了"middle"键,依旧可以找到上面的文档。

    当内嵌文档更加复杂之后,我们就需要更多的技巧了,如,有文档:

    > db.blog.find()
    { "_id" : 1, "title" : "1st post", "comments" : [       {       "author" : "joe"
    ,       "score" : 3 },  {       "author" : "marry",     "score" : 6 } ] }

    我们要找到评论者为joe,且score>=5的文档,如果我们采用:

    > db.blog.find({"comments.author":"joe","comments.score":{"$gte":5}})
    { "_id" : 1, "title" : "1st post", "comments" : [       {       "author" : "joe"
    ,       "score" : 3 },  {       "author" : "marry",     "score" : 6 } ] }

    来查找,明显是错误的,因为它返回了刚才的文档,因为第一条评论匹配了author:joe,第二条评论匹配了score:6.

    要正确的指定一组条件,而不用指定每个键,要使用"$elemMatch":

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

    "$elemMatch"将限定条件分组,仅当需要对一个内嵌文档的多个键操作时才会用到。

    8.$where查询

    $where子句可以执行任意JavaScript作为查询的一部分,这就使得查询几乎能做任何事。

    但是,它的性能比常规查询要慢很多,因为每个文档都要从BSON转换成JavaScript对象,然后通过$where表达式来运行,同时,还不能利用索引。

    因此,不是非常必要时,不要用$where子句。

    参考:mongodb权威指南

    备注:本节基本是《mongodb权威指南》第4章的笔记

  • 相关阅读:
    跨域常见解决方案
    express-session的简单使用说明
    Spring Cloud中,如何解决Feign/Ribbon第一次请求失败的问题?
    继承父类的静态方法的加载顺序
    sql索引优化
    EXPLAIN 执行计划详解
    JVM总括二-垃圾回收:GC Roots、回收算法、回收器
    dubbo知识体系
    Spring bean的生命流程
    日志体系与异常处理
  • 原文地址:https://www.cnblogs.com/tian2010/p/2607465.html
Copyright © 2020-2023  润新知