mongo.Aggregate.倚天劍.劍走偏鋒
熱愛武俠的人一定讀過金庸老先生寫的“倚天屠龍記”,寶刀屠龍,號令天下,莫敢不從,前4篇「Mongo儲存和效能最佳化」所展示的,可以說是屠龍刀,而現在我們即將描述的Aggregate就是倚天劍,倚天不出,誰也爭鋒。。
倚天劍裡面所藏武功,就是九陰白骨爪,下面讓我們一起來修行這個高深莫測的武功,廢話就到此為止,開始練功。
使用聚合框架可以對集合中文件進行變化和組合,可以用多個構件建立一個管道,用於對一連串的文件進行處理,構件有篩選,投影,分組,排序等。
下面介紹管道表示式,管道表示式可以理解為一個KV的結構,其中管道運算子作為“Key”,所對應的“Value”叫做管道表示式。例如{$match:{name:”zhangsan”}},$match稱為管道運算子,而{name:”zhangsan”}稱之為管道表示式,它稱之為管道運算子的運算元(Operand),每個管道表示式是一個文件結構,它是由欄位名、欄位值、和一些
表示式運算子
組成的,例如管道表示式$group: { _id: null, count: { $avg: 1 } } 就包含了一個表示式運算子$avg算平均值。
每個管道表示式只能作用於處理當前正在處理的文件,而不能進行跨文件的操作。管道表示式對文件的處理都是在記憶體中進行的。除了能夠進行累加計算的管道表示式外,其他的表示式都是無狀態的,也就是不會保留上下文的資訊,累加性質的表示式運算子通常和$group運算子一起使用,來統計該組內最大值、最小值等。
語法結構:
db。collection。aggregate
(
pipeline
,
options
) , pipeline 「資料的聚合操作」,Options「explain,allowDiskUse,cursor,maxTimeMS,bypassDocumentValidation,readConcern」 具體的詳細資訊,點選檢視官網文
當aggregate返回的結果集(指標或者結果集),當結果集中的單個文件超過16 MB命令會報錯;該限制只適用於返回的結果集文件,在管道處理文件的過程中,這個文件很有可能會超過16MB;
如果使用aggregate不指定遊標選項或儲存集合中的結果,aggregate命令返回一個包涵於結果集的欄位中的bson檔案。如果結果集的總大小超過bson檔案大小限制(16MB)該命令將產生錯誤;
管道處理階段有記憶體限制最大不能超過100MB,超過這個限制會報錯誤;為了能夠處理更大的資料集可以開啟allowDiskUse選項,可以將管道操作寫入臨時檔案;
下面著重介紹其中的管道運算子號:
九陰白骨爪之$match
簡介:透過指定的條件來過濾文件,然後傳給下一個管道
語法:{ $match: {
資料來源
{
“_id”
:
ObjectId
(
“512bc95fe835e68f199c8686”
),
“author”
:
“dave”
,
“score”
:
80
,
“views”
:
100
}
{
“_id”
:
ObjectId
(
“512bc962e835e68f199c8687”
),
“author”
:
“dave”
,
“score”
:
85
,
“views”
:
521
}
{
“_id”
:
ObjectId
(
“55f5a192d4bede9ac365b257”
),
“author”
:
“ahn”
,
“score”
:
60
,
“views”
:
1000
}
{
“_id”
:
ObjectId
(
“55f5a192d4bede9ac365b258”
),
“author”
:
“li”
,
“score”
:
55
,
“views”
:
5000
}
{
“_id”
:
ObjectId
(
“55f5a1d3d4bede9ac365b259”
),
“author”
:
“annT”
,
“score”
:
60
,
“views”
:
50
}
{
“_id”
:
ObjectId
(
“55f5a1d3d4bede9ac365b25a”
),
“author”
:
“li”
,
“score”
:
94
,
“views”
:
999
}
{
“_id”
:
ObjectId
(
“55f5a1d3d4bede9ac365b25b”
),
“author”
:
“ty”
,
“score”
:
95
,
“views”
:
1000
}
查詢語句
db
。
articles
。
aggregate
(
[
{
$match
:
{
author
:
“dave”
}
}
]
);
結果
:
{
“_id”
:
ObjectId
(
“512bc95fe835e68f199c8686”
),
“author”
:
“dave”
,
“score”
:
80
,
“views”
:
100
}
{
“_id”
:
ObjectId
(
“512bc962e835e68f199c8687”
),
“author”
:
“dave”
,
“score”
:
85
,
“views”
:
521
}
參考文章:
$match (aggregation)
九陰白骨爪之$project
簡介:傳給下一個管道所需要的欄位,欄位包含輸入文件存在的欄位和新的計算欄位
語法:{ $project: {
資料來源
{
“_id” : 1,
title: “abc123”,
isbn: “0001122223334”,
author: { last: “zzz”, first: “aaa” },
copies: 5
}
查詢語句
db。books。aggregate( [ { $project : { title : 1 , author : 1 } } ] )
輸出結果
{ “_id” : 1, “title” : “abc123”, “author” : { “last” : “zzz”, “first” : “aaa” } }
參考文章:
$project (aggregation)
九陰白骨爪之$group
簡介:按照指定的表示式來對文件進行分組,然後按照每一個分組傳給下一個管道,最後輸出對文件包含_id作為分組對Key,輸出對文件也包含計算的欄位的值。
語法:{ $group: { _id:
資料來源
{ “_id” : 1, “item” : “abc”, “price” : 10, “quantity” : 2, “date” : ISODate(“2014-03-01T08:00:00Z”) }
{ “_id” : 2, “item” : “jkl”, “price” : 20, “quantity” : 1, “date” : ISODate(“2014-03-01T09:00:00Z”) }
{ “_id” : 3, “item” : “xyz”, “price” : 5, “quantity” : 10, “date” : ISODate(“2014-03-15T09:00:00Z”) }
{ “_id” : 4, “item” : “xyz”, “price” : 5, “quantity” : 20, “date” : ISODate(“2014-04-04T11:21:39。736Z”) }
{ “_id” : 5, “item” : “abc”, “price” : 10, “quantity” : 10, “date” : ISODate(“2014-04-04T21:23:13。331Z”) }
查詢語句
db。sales。aggregate(
[
{
$group : {
_id : { month: { $month: “$date” }, day: { $dayOfMonth: “$date” }, year: { $year: “$date” } },
totalPrice: { $sum: { $multiply: [ “$price”, “$quantity” ] } },
averageQuantity: { $avg: “$quantity” },
count: { $sum: 1 }
}
}
]
)
輸出結果
{ “_id” : { “month” : 3, “day” : 15, “year” : 2014 }, “totalPrice” : 50, “averageQuantity” : 10, “count” : 1 }
{ “_id” : { “month” : 4, “day” : 4, “year” : 2014 }, “totalPrice” : 200, “averageQuantity” : 15, “count” : 2 }
{ “_id” : { “month” : 3, “day” : 1, “year” : 2014 }, “totalPrice” : 40, “averageQuantity” : 1。5, “count” : 2 }
參考文章
$group (aggregation)
九陰白骨爪之$unwind
簡介:將輸入文件中的陣列,分割成對應的一個文件,陣列中的一個值對應一個文件
語法:{
$unwind:
{
path:
includeArrayIndex:
preserveNullAndEmptyArrays: <
boolean
>
}
}
資料來源
{ “_id” : 1, “item” : “ABC1”, sizes: [ “S”, “M”, “L”] }
查詢語句
db。inventory。aggregate( [ { $unwind : “$sizes” } ] )
輸出結果
{ “_id” : 1, “item” : “ABC1”, “sizes” : “S” }
{ “_id” : 1, “item” : “ABC1”, “sizes” : “M” }
{ “_id” : 1, “item” : “ABC1”, “sizes” : “L” }
參考文章
https://
docs。mongodb。com/manual
/reference/operator/aggregation/unwind/
九陰白骨爪之$limit
簡介:限制傳遞給下一個管道的文件數量
語法:{ $limit:
db。article。aggregate(
{ $limit : 5 }
);
參考文章:
$limit (aggregation)
九陰白骨爪之$skip
簡介:跳過指定數量的文件,傳遞剩餘的文件到下一個管道
語法:{ $skip:
db。article。aggregate(
{ $skip : 5 }
);
參考文章
$skip (aggregation)
九陰白骨爪之$sort
簡介:排序所有的文件傳給下一個管道
語法 :{ $sort: {
db。users。aggregate(
[
{ $sort : { age : -1, posts: 1 } }
]
)
參考文章
$sort (aggregation)
九陰白骨爪之$lookup
簡介:在同一個資料庫執行左外連線,來過濾相關的文件,傳遞給下一個管道
語法:{
$lookup:
{
from:
localField:
foreignField:
as:
}
}
資料來源:
db。orders。insert([
{ “_id” : 1, “item” : “almonds”, “price” : 12, “quantity” : 2 },
{ “_id” : 2, “item” : “pecans”, “price” : 20, “quantity” : 1 },
{ “_id” : 3 }
])
db。inventory。insert([
{ “_id” : 1, “sku” : “almonds”, description: “product 1”, “instock” : 120 },
{ “_id” : 2, “sku” : “bread”, description: “product 2”, “instock” : 80 },
{ “_id” : 3, “sku” : “cashews”, description: “product 3”, “instock” : 60 },
{ “_id” : 4, “sku” : “pecans”, description: “product 4”, “instock” : 70 },
{ “_id” : 5, “sku”: null, description: “Incomplete” },
{ “_id” : 6 }
])
查詢語句:
db。orders。aggregate([
{
$lookup:
{
from: “inventory”,
localField: “item”,
foreignField: “sku”,
as: “inventory_docs”
}
}
])
輸出結果
{
“_id” : 1,
“item” : “almonds”,
“price” : 12,
“quantity” : 2,
“inventory_docs” : [
{ “_id” : 1, “sku” : “almonds”, “description” : “product 1”, “instock” : 120 }
]
}
{
“_id” : 2,
“item” : “pecans”,
“price” : 20,
“quantity” : 1,
“inventory_docs” : [
{ “_id” : 4, “sku” : “pecans”, “description” : “product 4”, “instock” : 70 }
]
}
{
“_id” : 3,
“inventory_docs” : [
{ “_id” : 5, “sku” : null, “description” : “Incomplete” },
{ “_id” : 6 }
]
}
參考文章
$lookup (aggregation)
九陰白骨爪之$count
簡介:統計文件的數量傳遞給下一個管道
語法:{ $count:
資料來源
{ “_id” : 1, “subject” : “History”, “score” : 88 }
{ “_id” : 2, “subject” : “History”, “score” : 92 }
{ “_id” : 3, “subject” : “History”, “score” : 97 }
{ “_id” : 4, “subject” : “History”, “score” : 71 }
{ “_id” : 5, “subject” : “History”, “score” : 79 }
{ “_id” : 6, “subject” : “History”, “score” : 83 }
查詢語句
db。scores。aggregate(
[
{
$match: {
score: {
$gt: 80
}
}
},
{
$count: “passing_scores”
}
]
)
輸出結果
{ “passing_scores” : 4 }
參考文章
$count (aggregation)
九陰白骨爪之$redact
簡介:根據文件本身儲存的資訊來限制文件
語法:{ $redact:
資料來源
{
_id: 1,
title: “123 Department Report”,
tags: [ “G”, “STLW” ],
year: 2014,
subsections: [
{
subtitle: “Section 1: Overview”,
tags: [ “SI”, “G” ],
content: “Section 1: This is the content of section 1。”
},
{
subtitle: “Section 2: Analysis”,
tags: [ “STLW” ],
content: “Section 2: This is the content of section 2。”
},
{
subtitle: “Section 3: Budgeting”,
tags: [ “TK” ],
content: {
text: “Section 3: This is the content of section3。”,
tags: [ “HCS” ]
}
}
]
}
查詢語句
var userAccess = [ “STLW”, “G” ];
db。forecasts。aggregate(
[
{ $match: { year: 2014 } },
{ $redact: {
$cond: {
if: { $gt: [ { $size: { $setIntersection: [ “$tags”, userAccess ] } }, 0 ] },
then: “$$DESCEND”,
else: “$$PRUNE”
}
}
}
]
);
輸出結果
{
“_id” : 1,
“title” : “123 Department Report”,
“tags” : [ “G”, “STLW” ],
“year” : 2014,
“subsections” : [
{
“subtitle” : “Section 1: Overview”,
“tags” : [ “SI”, “G” ],
“content” : “Section 1: This is the content of section 1。”
},
{
“subtitle” : “Section 2: Analysis”,
“tags” : [ “STLW” ],
“content” : “Section 2: This is the content of section 2。”
}
]
}
參考文章
$redact (aggregation)
九陰白骨爪果真是門邪惡的武功,頭痛無比,夜已深,在寫非得走火入魔,下期再見 九陰白骨爪。橫掃千軍。。。。。