• MongoDB M001第五章 索引和聚合管道


    聚合框架

    • 聚合框架:只是在MongoDB中查询数据的另一种方式。聚合操作放在 []

    • 聚合框架语法:采用管道的形式,其中阶段按照它们列出的顺序执行。

    • MongoDB Aggregation Framework($group)(计算&重塑数据) > MongoDB Query Language(MQL)(过滤&更新数据)

    • MQL和聚合框架写法区别(Eg: 查找所有将 Wifi 作为便利设施之一的 文档。只在结果游标中包含价格 和 地址)

      • // MQL(MongoDB Query Language:)
        db.listingsAndReviews.find({ "amenities": "Wifi" },
                                   { "price": 1, "address": 1, "_id": 0 }).pretty()
        
        // 聚合框架:
        db.listingsAndReviews.aggregate([
                                          { "$match": { "amenities": "Wifi" } },
                                          { "$project": { "price": 1,
                                                          "address": 1,
                                                          "_id": 0 }}]).pretty()
        
    • 使用聚合而不是MQL查找的原因:

      1. 因为有时候可能用聚合:比如分组操作,以某种方式修改数据。

      2. 并不是总是只需要过滤出正确的文档。

      3. 可以执行除了 查找、投影数据 以外的操作,比如使用聚合进行计算。

      4. 它通过计算、重塑、重组数据的能力 超越了 MQL的 过滤能力。(聚合框架允许我们通过使用\(group、\)sum等阶段来计算和重塑数据。)

    • 管道操作顺序

      • 聚合框架用作管道,管道中的操作顺序很重要
    • 聚合管道数据

      • 数据在管道中是如何处理的?

        • 我们在管道的一端,将数据提供给管道->我们描述了该管道将如何使用聚合阶段处理我们的数据->转换后的数据出现在管道末端。
      • 聚合管道中的数据存在于管道内,本质上不会修改原始数据

    聚合框架例子

    • Eg1: 每个_id按照不同类别的price去计数: "total": { "$sum": "$price" }

    • Eg2: 在集合中查找一个文档,并且只 在结果游标中包含地址 字段。

      • db.listingsAndReviews.findOne({ },{ "address": 1, "_id": 0 })
    • Eg3: 仅 投影每个文档的地址 字段值,然后将所有文档分组为每个 address.country 值的一个文档,并为每个组中的每个文档计数一个。

      • db.listingsAndReviews.aggregate([
                                          { "$project": { "address": 1, "_id": 0 }},
                                          { "$group": { "_id": "$address.country",
                                                        "count": { "$sum": 1 } } }
                                        ])
        
    • Eg4: What room types are present in the sample_airbnb.listingsAndReviews collection? 字段:room_type:"xxx"

      • db.listingsAndReviews.aggregate([
                                          { "$project": { "room_type": 1}},
                                          { "$group": { "_id": "$room_type",
                                                        "count": { "$sum": 1 } } }
                                        ])
        
        Answer: db.listingsAndReviews.aggregate([ { "$group": { "_id": "$room_type" } }])
        
        output:
        ...                               
        [
          { _id: 'Entire home/apt', count: 3489 },
          { _id: 'Private room', count: 1983 },
          { _id: 'Shared room', count: 83 }
        ]
        
    • Eg5: 以下哪个命令将返回sample_training.companies集合中5 家历史最悠久的公司的名称和成立年份 ?

      • // 错 
        db.companies.find({}, { "name": 1, "founded_year": 1 }). sort({ "founded_year": 1 }).limit(5)
        // 此命令缺少搜索条件,这意味着将包含空值。排除空值并不总是必要的,因为无论如何将这些类型的值存储在 MongoDB 中并不是最佳实践。所以有很多集合没有空值。然而,这个集合包含空值,我们需要从我们的游标中排除它们,否则在我们排序时它们将是我们的最小值。
        
        // 对
        db.companies.find({ "founded_year": {"$ne":null}},{"name":1,"founded_year": 1}).sort({ "found_year": 1 }).limit(5)
        // 我们首先必须过滤出成立年份不为空的文档,然后投影我们要查找的字段,即名称, 在本例中为founded_year。然后我们按升序对光标进行排序,因此第一个结果将具有found_year字段的最小值。最后,我们将结果限制在游标中的前5 个文档,从而获得 此集合中最古老的5 个公司。
        
        // 对
        db.companies.find({ "founded_year": {"$ne":null}},{"name":1,"founded_year": 1}).limit(5).sort({ "found_year": 1 })
        // 虽然limit()和sort()方法未按正确顺序列出,但 MongoDB 在执行查询时会翻转它们的顺序,提供问题提示正在寻找的结果。
        
        // 错
        db.companies.find({ "name":1,"founded_year": 1}).sort({ "founded_year": 1 }).limit(5)
        // 看起来查询过滤器具有find()命令的投影部分 应该具有的值,并且此命令中没有使用投影。所以这个命令将返回所有 name 等于 1并且created_year也等于1 的公司,不幸的是它错过了问题提示的要求。
        

    sort() & limit()

    • sort() & limit() 是游标方法,其他的游标方法有:pretty() , count()

      • 游标方法不适用于:存储在数据库中的数据,它应用于位于游标中的结果集。

      • 这两个一般结合使用,先执行 sort 再执行 limit ,如果``cursor.limit().sort()了,内部执行的还是cursor.sort().limit()` 。

    • sort排序语法:db.COLLECTION_NAME.find().sort({KEY:1,key2:-1});

      • 其中 1 为升序排列,而-1为降序排列
    • Eg1:

      • // 按照人口递增顺序排序,返回第一个文档 = 取人口最少的文档
        db.zips.find().sort({ "pop": 1 }).limit(1)  
        
        // 按照人口递增减序排序,返回第一个文档 = 取人口最多的文档
        db.zips.find().sort({ "pop": -1 }).limit(1) 
        
        // 多个排序
        db.zips.find().sort({ "pop": 1, "city": -1 }) 
        
    • Eg2: sample_training.trips 系列中最年轻的自行车骑手是哪一年出生的?

      • 错:db.trips.find( {"birth year":{"$ne":null} } ).sort({"birth year":-1}).limit(1)  注意第一个花括号要写的
        
        错:db.trips.find({ "birth year": {"$ne":null}},{"birth year": 1}).sort({ "birth year": -1 }).limit(1)
        
        对:  db.trips.find({ "birth year": { "$ne":"" } },
                             { "birth year": 1 }).sort({ "birth year": -1 }).limit(1)
        // 过滤空字符串 而不是null
        

    index

    • 是什么

      • 索引是一种特殊的数据结构,以易于遍历的形式存储 集合数据集的一小部分
    • 作用:使查询高效

      • 有很多种方式可以优化查询速度,但是最有效的方式是 添加索引(Indexes)
    • 总结:简单来说,索引是一种 优化查询速度 的 数据结构

    • Eg:

      • db.trips.find({ "birth year": 1989 })
        
        // 创建单个字段索引 single field index = 单一字段
        db.trips.createIndex({ "birth year": 1 })
        
        //如果碰到db.trips.find({ "start station id": 476 }).sort( { "birth year": 1 } ) 这种情况
        
        // 为了使第二次查询更高效,需使用复合索引
        db.trips.createIndex({ "start station id": 1, "birth year": 1 })
        

    数据建模

    • 数据建模是什么:一种在文档中组织字段以支持应用程序性能和查询功能的方法。

    • 默认情况下,MongoDB并不强制执行默认的数据组织方式。

    • 那么如何决定用什么结构来存储数据?应该在哪创建子文件?应该在哪用数值数组?在哪一点上,数据应该得到自己的集合?对数据的形状和结构做出这些决定被称为数据建模。 数据建模是一种 在文件中组织字段以支持应用程序 性能和查询功能 的方法。

    • 数据以使用的方式存储。在用MongoDB进行数据建模时,那些被一起访问的数据应该被存储在一起。

    • 当应用程序在变化和发展时,你的数据模型也应该在不断发展。而MongoDB是为快速的数据模型变化和进化而建立的。

    Upsert

    • Upsert是什么:更新和插入混合体。

    • 语法:db.collection_name.updateOne( {<query>}, {<update>}, {"upsert":true})

      • 默认情况下 upsertfalse ,如果为 true 则可以执行更新/插入操作。有则更新,无则插入
  • 相关阅读:
    hdu5514 非2的次幂容斥原理
    「NOIP2015」斗地主
    「NOIP2009」靶形数独
    「CF521D」Shop
    「HNOI2015」菜肴制作
    「NOIP2011」观光公交
    「NOI2015」荷马史诗
    「JSOI2007」建筑抢修
    「CF161B」Discounts
    叠罗汉
  • 原文地址:https://www.cnblogs.com/OFSHK/p/15640895.html
Copyright © 2020-2023  润新知