zoukankan      html  css  js  c++  java
  • mongodb-管道操作:常规查询

    MongoDB:管道操作

    使用聚合框架可以对集合中的文档进行变换和组合。基本上,可以用多个构件创建一个管道(pipeline),用于对一连串的文档进行处理。这些构件包括筛选(filter)、投射(projecting)、分组(grouping)、排序(sorting)、限制(limiting)和跳过(skipping)。

    例如,有一个保存书籍信息的集合,你想知道投票数量最多的书籍。可以按照如下步骤创建管道:

    • 将每个书籍信息中的书名和投票投射出来{"$project":{"title":1,"vote_num":1}}
    • 统计每个书名所有的投票数(书名可能重复){"$group":{"_id":"$title","vote_num":{"$sum":"$vote_num"}}}
    • 按照投票数降序排列{"$sort":{"vote_num":-1}}
    • 将返回结果限制为前5个{"$limit":5}
    db.book_info.aggregate({"$project":{"title":1,"vote_num":1}},{"$group":{"_id":"$title","vote_num":{"$sum":"$vote_num"}}},{"$sort":{"vote_num":-1}},{"$limit":5})

    结果

    { "_id" : "小王子", "vote_num" : 265438 }
    { "_id" : "活着", "vote_num" : 263733 }
    { "_id" : "追风筝的人", "vote_num" : 253532 }
    { "_id" : "白夜行", "vote_num" : 232564 }
    { "_id" : "梦里花落知多少", "vote_num" : 204792 }

    $match

    $match用于对文档集合记性筛选,之后就可以在筛选得到的文档子集上做聚合。

    db.book_info.aggregate({"$match":{"title":"小王子"}},{"$project":{"title":1,"vote_num":1}})

    结果

    { "_id" : ObjectId("58d3972be13823416ede764c"), "title" : "小王子", "vote_num" : 210926 }
    { "_id" : ObjectId("58d397c6e13823416ede823c"), "title" : "小王子", "vote_num" : 10273 }
    { "_id" : ObjectId("58d398a6e13823416ede930a"), "title" : "小王子", "vote_num" : 3748 }
    ...

    match使"

    gt”、”lt""

    in”等)

    db.book_info.aggregate({"$match":{"title":"小王子","vote_num":{"$lt":100}}},{"$project":{"title":1,"vote_num":1}})

    结果

    { "_id" : ObjectId("58d39d27e13823416edeec07"), "title" : "小王子", "vote_num" : 65 }
    { "_id" : ObjectId("58d39e33e13823416edf01e4"), "title" : "小王子", "vote_num" : 91 }
    { "_id" : ObjectId("58d39f2fe13823416edf1670"), "title" : "小王子", "vote_num" : 93 }
    ...

    $project

    使用$project操作,可以从子文档中提取字段,可以重命名字段,还可以再这些字段上进行一些有意思的操作。

    选择想要的字段

    db.book_info.aggregate({"$project":{"title":1,"vote_num":1}})

    结果

    { "_id" : ObjectId("58d39725e13823416ede75f0"), "title" : "一个陌生女人的来信", "vote_num" : 38478 }
    { "_id" : ObjectId("58d39725e13823416ede75f1"), "title" : "猎豹", "vote_num" : 598 }
    { "_id" : ObjectId("58d39725e13823416ede75f2"), "title" : "酝酿之道", "vote_num" : 32 }
    ...

    重命名字段。这里的$vote_num语法是为了在聚合框架中引用vote_num字段

    db.book_info.aggregate({"$project":{"title":1,"vote_num_rename":"$vote_num"}})

    结果

    { "_id" : ObjectId("58d39725e13823416ede75f0"), "title" : "一个陌生女人的来信", "vote_num_rename" : 38478 }
    { "_id" : ObjectId("58d39725e13823416ede75f1"), "title" : "猎豹", "vote_num_rename" : 598 }
    { "_id" : ObjectId("58d39725e13823416ede75f2"), "title" : "酝酿之道", "vote_num_rename" : 32 }

    $project还支持如下表达式

    数学表达式

    • “$add”:[expr1[,expr2,…,exprN]] 接受一个或多个表达式作为参数,将这些表达式相加
    • “$subtract”:[expr1,expr2] 接受两个表达式作为参数,用第一个表达式减去第二个表达式作为结果
    • “$multiply”:[expr1[,expr2,…,exprN]] 接受一个或多个表达式,并且将他们相乘
    • “$divide”:[expr1,expr2] 接受两个表达式,用第一个表达式除以第二个表达式的商作为结果
    • “$mod”:[expr1,expr2] 接受两个表达式,将第一个表达式除以第二个表达式得到的余数作为结果

    日期表达式(只能对日期类型的字段进行日期操作,不能对数值类型字段做日期操作)

    • $year
    • $month
    • $week
    • $dayOfMonth
    • $dayOfWeek
    • $dayOfYear
    • $hour

    字符串表达式

    • “$substr”:[expr,startOffset,numToReturn] 截取字符串的子串,从startOffset字节开始,一共numToReturn个字节
    • “$concat”:[expr1[,expr2,…,exprN]] 将给定的表达式(或字符串)连接在一起作为返回结果
    • “$toLower”:expr expr必须是字符串,返回expr的小写形式
    • “$toUpper”:expr 返回expr的大写形式

    逻辑表达式

    • “$cmp”:[expr1,expr2] 比较expr1和expr2,如果相等返回0,expr1

    $group

    $group操作可以将文档依据特定字段的不同值进行分组。

    db.book_info.aggregate({"$project":{"title":1,"vote_num":1}},{"$group":{"_id":"$title","count":{"$sum":1}}})

    结果

    { "_id" : "jQuery实战", "count" : 3 }
    { "_id" : "Casanova Was a Book Lover", "count" : 1 }
    { "_id" : "Chris Killip", "count" : 1 }
    ...

    算数操作符

    • “$sum”:value 求和
    • “$avg”:value 求平均值

    极值操作符

    • “$max”:expr 返回组内的最大值
    • “$min”:expr 返回组内的最小值
    • “$first”:expr 返回分组的第一个值
    • “$last”:expr 返回分组的最后一个值

    数组操作符

    • “$addToSet”:expr 如果当前数组不包含expr,则将其添加到数组中,在返回结果集中,每个元素最多出现1次,而且元素的顺序是不确定的
    • “$push”:expr 不管expr是什么值,都将它添加到数组中,返回包含所有值的数组

    $unwind

    拆分可以将数组中的每一个值拆分成单独的文档。例如

    > db.book_info.find({},{"title":1,"tags":1})
    { "_id" : ObjectId("58d39725e13823416ede75f0"), "title" : "一个陌生女人的来信", "tags" : [ "茨威格", "一个陌生女人的来信", "外国文学", "爱情", "小说", "奥地利", "经典", "文学" ] }
    { "_id" : ObjectId("58d39725e13823416ede75f1"), "title" : "猎豹", "tags" : [ "犯罪小说", "推理", "悬疑", "尤?奈斯博", "小说", "外国文学", "北欧", "人性" ] }
    ...
    
    db.book_info.aggregate({"$project":{"title":1,"tags":1}},{"$unwind":"$tags"})
    { "_id" : ObjectId("58d39725e13823416ede75f0"), "title" : "一个陌生女人的来信", "tags" : "茨威格" }
    { "_id" : ObjectId("58d39725e13823416ede75f0"), "title" : "一个陌生女人的来信", "tags" : "一个陌生女人的来信" }
    { "_id" : ObjectId("58d39725e13823416ede75f0"), "title" : "一个陌生女人的来信", "tags" : "外国文学" }
    { "_id" : ObjectId("58d39725e13823416ede75f0"), "title" : "一个陌生女人的来信", "tags" : "爱情" }
    { "_id" : ObjectId("58d39725e13823416ede75f0"), "title" : "一个陌生女人的来信", "tags" : "小说" }
    { "_id" : ObjectId("58d39725e13823416ede75f0"), "title" : "一个陌生女人的来信", "tags" : "奥地利" }
    { "_id" : ObjectId("58d39725e13823416ede75f0"), "title" : "一个陌生女人的来信", "tags" : "经典" }
    { "_id" : ObjectId("58d39725e13823416ede75f0"), "title" : "一个陌生女人的来信", "tags" : "文学" }
    { "_id" : ObjectId("58d39725e13823416ede75f1"), "title" : "猎豹", "tags" : "犯罪小说" }
    { "_id" : ObjectId("58d39725e13823416ede75f1"), "title" : "猎豹", "tags" : "推理" }
    { "_id" : ObjectId("58d39725e13823416ede75f1"), "title" : "猎豹", "tags" : "悬疑" }
    { "_id" : ObjectId("58d39725e13823416ede75f1"), "title" : "猎豹", "tags" : "尤·奈斯博" }
    { "_id" : ObjectId("58d39725e13823416ede75f1"), "title" : "猎豹", "tags" : "小说" }
    { "_id" : ObjectId("58d39725e13823416ede75f1"), "title" : "猎豹", "tags" : "外国文学" }
    { "_id" : ObjectId("58d39725e13823416ede75f1"), "title" : "猎豹", "tags" : "北欧" }
    { "_id" : ObjectId("58d39725e13823416ede75f1"), "title" : "猎豹", "tags" : "人性" }
    ...

    $sort

    可以根据任何字段(或者多个字段)进行排序,与在普通查询中的语法是相同的。如果要对大量的文档进行排序,强烈建议在管道的第一阶段进行排序,这时的排序操作可以使用索引。否则,排序过程就会比较慢,而且会占用大量内存。

    1是升序,-1是降序

    db.book_info.aggregate({"$project":{"title":1,"vote_num":1}},{"$sort":{"vote_num":-1}})

    结果

    { "_id" : ObjectId("58d39726e13823416ede75ff"), "title" : "追风筝的人", "vote_num" : 247079 }
    { "_id" : ObjectId("58d3972be13823416ede764c"), "title" : "小王子", "vote_num" : 210926 }
    { "_id" : ObjectId("58d3972ae13823416ede7641"), "title" : "围城", "vote_num" : 179228 }
    { "_id" : ObjectId("58d3972de13823416ede766a"), "title" : "白夜行", "vote_num" : 172310 }
    { "_id" : ObjectId("58d39725e13823416ede75f3"), "title" : "解忧杂货店", "vote_num" : 166469 }
    ...

    $limit

    $limit接受一个数字n,返回结果集中的前n个文档

    db.book_info.aggregate({"$limit":5})

    $skip

    $skip接受一个数字n,表示丢弃结果集中的前n个文档。如果需要跳过大量的数据,那么这个操作符的效率会比较低。

    db.book_info.aggregate({"$skip":5})
  • 相关阅读:
    CF869E The Untended Antiquity 解题报告
    Walk 解题报告
    CF911F Tree Destruction 解题报告
    P4397 [JLOI2014]聪明的燕姿
    洛谷 P2329 [SCOI2005]栅栏 解题报告
    洛谷 P3747 [六省联考2017]相逢是问候 解题报告
    set-erase
    set-empty
    set-empty
    set-end
  • 原文地址:https://www.cnblogs.com/wangyuxing/p/9923206.html
Copyright © 2011-2022 走看看