您當前的位置:首頁 > 書法

mongo.Aggregate.倚天劍.劍走偏鋒

作者:由 swordman 發表于 書法時間:2019-03-12

熱愛武俠的人一定讀過金庸老先生寫的“倚天屠龍記”,寶刀屠龍,號令天下,莫敢不從,前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)

九陰白骨爪果真是門邪惡的武功,頭痛無比,夜已深,在寫非得走火入魔,下期再見 九陰白骨爪。橫掃千軍。。。。。

標簽: id  文件  score  管道  aggregate