View a markdown version of this page

$setWindowFields - Amazon DocumentDB

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

$setWindowFields

8.0.2 版的新功能。

Amazon DocumentDB 中的$setWindowFields階段會對分割區中指定的文件範圍 (視窗) 執行操作,並根據選擇的視窗運算子傳回結果。階段會將輸入文件分組為分割區,選擇性地對其進行排序,並且對於每個文件, 會在包圍文件的視窗中計算一個或多個輸出欄位。

語法

{ $setWindowFields: { partitionBy: <expression>, sortBy: { <sortField1>: <sortOrder>, ... }, output: { <outputField1>: { <windowOperator>: <expression>, window: { documents: [ <lowerBound>, <upperBound> ], range: [ <lowerBound>, <upperBound> ], unit: <time unit> } }, ... } } }

參數

  • partitionBy:選用。用於將文件分組為分割區的單一表達式。這可以是欄位路徑 (例如 "$state") 或其他表達式。如果省略,所有輸入文件都屬於單一分割區。

  • sortBy:選用。指定欄位的文件,以遞增{ <field>: 1 }順序或{ <field>: -1 }遞減順序的形式排序每個分割區中的文件。當您使用文件型或範圍型視窗邊界,以及使用其中一個排名運算子時, sortBy 是必要的。

  • output:必要。指定要附加到每個文件的欄位的文件。您可以指定多個輸出欄位,但每個輸出欄位只需要一個視窗運算子、其引數,以及定義視窗邊界的選用window文件:{ <field>: { <windowOperator>: <expression>, window: { ... } } }。

視窗邊界

在每個output欄位中,您可以選擇使用window文件定義視窗邊界。視窗可以依文件位置或值範圍來定義。

  • documents:將視窗指定為目前文件前後的文件數量,格式為 [ <lowerBound>, <upperBound> ]。每個邊界都是整數位移 (例如 -1或 2),或其中一個關鍵字 "unbounded"和 "current"。當用作下限時, 會將視窗"unbounded"延伸到分割區的開頭,當用作上限時延伸到分割區的結尾。 "current"表示目前的文件。除非兩個邊界都是 ,sortBy否則documents視窗都需要 "unbounded"。

  • range:將視窗指定為相對於目前文件sortBy的欄位值範圍,格式為 [ <lowerBound>, <upperBound> ]。每個邊界都是新增至目前文件或"unbounded"關鍵字sortBy值的數字。range 視窗只需要一個遞增sortBy欄位,而且不接受"current"關鍵字。

  • unit:選用。搭配 使用range,將數值視窗邊界解譯為sortBy欄位保留日期值的時間範圍。Amazon DocumentDB 支援下列單位:"year"、"quarter"、"month"、"week"、"day"、"hour"、"minute"、 "second"和 "millisecond"。指定 unit 時,range邊界必須是整數。

省略window文件時,預設視窗為 documents: ["unbounded", "unbounded"],跨越整個分割區。

注意

當您使用一段時間內的range時段值時,我們建議固定持續時間,unit例如 "day"(或更小),而不是 "month"、 "quarter"或 "year",其行事曆相依的長度可能會產生不明確的時段界限。

支援的視窗運算子

Amazon DocumentDB 在$setWindowFields階段的 output 欄位中支援下列 26 個視窗運算子:

  • $sum

  • $avg

  • $count

  • $push

  • $addToSet

  • $stdDevPop

  • $stdDevSamp

  • $covariancePop

  • $covarianceSamp

  • $first

  • $last

  • $firstN

  • $lastN

  • $top

  • $bottom

  • $topN

  • $bottomN

  • $min

  • $minN

  • $max

  • $maxN

  • $median

  • $percentile

  • $rank

  • $denseRank

  • $documentNumber

注意

$setWindowFields 階段中的視窗$rand運算子不支援 運算子。

空白視窗

當視窗不包含文件 (例如,範圍中沒有值的range視窗) 時,結果取決於運算子: $count 和 $sum 傳回 0;$push、$addToSet、$firstN$lastN、$topN、、 和 $minN $maxN$bottomN傳回空陣列; $percentile 傳回null值陣列 (每個請求的百分位數一個);所有其他運算子傳回 null。

範例 (MongoDB Shell)

下列範例會依 分割文件region、依 排序每個分割區day,並計算revenue從分割區開頭到目前文件的執行中總數 。

建立範例文件

db.sales.insertMany([ { _id: 1, region: "east", day: 1, revenue: 100 }, { _id: 2, region: "east", day: 2, revenue: 150 }, { _id: 3, region: "east", day: 3, revenue: 120 }, { _id: 4, region: "west", day: 1, revenue: 200 }, { _id: 5, region: "west", day: 2, revenue: 180 } ]);

查詢範例

db.sales.aggregate([ { $setWindowFields: { partitionBy: "$region", sortBy: { day: 1 }, output: { runningRevenue: { $sum: "$revenue", window: { documents: ["unbounded", "current"] } } } } } ]);

輸出

[ { "_id": 1, "region": "east", "day": 1, "revenue": 100, "runningRevenue": 100 }, { "_id": 2, "region": "east", "day": 2, "revenue": 150, "runningRevenue": 250 }, { "_id": 3, "region": "east", "day": 3, "revenue": 120, "runningRevenue": 370 }, { "_id": 4, "region": "west", "day": 1, "revenue": 200, "runningRevenue": 200 }, { "_id": 5, "region": "west", "day": 2, "revenue": 180, "runningRevenue": 380 } ]

每個文件都會以 擴增runningRevenue,即其分割區revenue內累計的 總和,最多可達並包含目前的文件。

程式碼範例

若要檢視使用$setWindowFields階段的程式碼範例,請選擇您要使用的語言標籤:

Node.js
const { MongoClient } = require('mongodb'); async function example() { const client = new MongoClient('mongodb://<username>:<password>@<cluster-endpoint>:27017/?tls=true&tlsCAFile=global-bundle.pem&replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false'); try { await client.connect(); const db = client.db('test'); const sales = db.collection('sales'); await sales.insertMany([ { _id: 1, region: "east", day: 1, revenue: 100 }, { _id: 2, region: "east", day: 2, revenue: 150 }, { _id: 3, region: "east", day: 3, revenue: 120 }, { _id: 4, region: "west", day: 1, revenue: 200 }, { _id: 5, region: "west", day: 2, revenue: 180 } ]); const result = await sales.aggregate([ { $setWindowFields: { partitionBy: "$region", sortBy: { day: 1 }, output: { runningRevenue: { $sum: "$revenue", window: { documents: ["unbounded", "current"] } } } } } ]).toArray(); console.log(result); } finally { await client.close(); } } example();
Python
from pymongo import MongoClient def example(): client = MongoClient('mongodb://<username>:<password>@<cluster-endpoint>:27017/?tls=true&tlsCAFile=global-bundle.pem&replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false') try: db = client['test'] sales = db['sales'] sales.insert_many([ { '_id': 1, 'region': 'east', 'day': 1, 'revenue': 100 }, { '_id': 2, 'region': 'east', 'day': 2, 'revenue': 150 }, { '_id': 3, 'region': 'east', 'day': 3, 'revenue': 120 }, { '_id': 4, 'region': 'west', 'day': 1, 'revenue': 200 }, { '_id': 5, 'region': 'west', 'day': 2, 'revenue': 180 } ]) result = list(sales.aggregate([ { '$setWindowFields': { 'partitionBy': '$region', 'sortBy': { 'day': 1 }, 'output': { 'runningRevenue': { '$sum': '$revenue', 'window': { 'documents': ['unbounded', 'current'] } } } } } ])) print(result) finally: client.close() example()