Let

說明

定義可在管道後續階段參照的暫時變數。

除非明確指派給後續階段的欄位 (例如使用 add_fields(...)select(...)),否則在 let(...) 階段建立的變數不會納入最終結果。您可以將複雜的邏輯分解為較小的可重複使用元件,簡化邏輯,同時避免輸出文件雜亂無章。let(...) 階段特別適合用於相關子管道,因為子管道需要參照父項文件範圍中的值。

範例

Node.js

const results = await db.pipeline()
  .collection("/awards")
  // `let(...)` referred to as `define(...)` in the Web SDK.
  .define(rand().as("r"))
  .addFields(
    switchOn(
      lessThan(variable("r"), 0.05), constant("rare"),
      lessThan(variable("r"), 0.25), constant("uncommon"),
      constant("common")).as("random_score"))
  .execute();

行為

變數與欄位

欄位代表儲存在文件中的資料,變數則是僅在管道執行期間存在的暫時值。

欄位 變數
目的 存取欄位或將欄位儲存至文件中 在管道執行期間產生或存取暫時值
SDK 使用情形 field("name") variable("name")
範圍 目前文件所在位置 從全域到管道和子管道
未定義的參照 評估結果為 absent 產生執行階段錯誤

範圍:

欄位會限定在本地文件中,變數則是在個別範圍中定義,且在「合併」多個文件的階段首次出現之前,變數在各階段中都可存取 (例如 aggregate(...)distinct(...))。「合併」多個文件的階段不允許之後使用變數參照,因為合併先前階段的結果後,變數就不再有單一值。

做法:篩選文件欄位後,再參照變數。

Node.js

const results = db.pipeline()
  .collection("/awards")
  .define(min(field("score").abs(), constant(100)).as("normalized_score"))
  .select(field("__name__"), field("owner_id"))
  // Successfully able to use the variable.
  .where(variable("normalized_score").greaterThan(10))
  .execute();

請勿:在匯總參照變數。

Node.js

const results = db.pipeline()
  .collection("/awards")
  .define(min(field("score").abs(), constant(100)).as("normalized_score"))
  .aggregate({
    accumulators: [ field("score").avg().as("avg_score") ],
    groups: [ field("owner_id") ]
  })
  // Attempting to use the variable throws a request validation error.
  .where(variable("normalized_score").greaterThan(10))
  .execute();

未定義的參照:

參考未定義的欄位沒問題 (只會評估為 absent),但嘗試參考未定義的變數時,要求驗證會失敗。就這個意義而言,欄位參照可視為在執行階段執行地圖中的查閱作業,而變數參照則較類似於靜態編譯程式設計語言中的變數。

全域範圍和子查詢

使用巢狀管道時,變數至關重要。子管道會在自己的範圍內執行,且只能存取目前處理的文件欄位。如要在子查詢中使用「父項」文件中的值,必須先使用 let(...) 階段將該值定義為變數。

Node.js

// Fetch reviewers alongside their negative reviews.
const pipeline = db.pipeline()
  .collection("/reviewers")
  // `let(...)` referred to as `define(...)` in the Web SDK.
  .define(field("__name__").as("reviewer_name"))
  .select("__name__", array(db.pipeline().collectionGroup("reviews")
    .where(field("author").equals(variable("reviewer_name")))
    .where(field("rating").lessThan(2))
    .select("review", "rating")).as("negative_reviews"))
  .execute();

重疊變數

如果定義的變數名稱與先前 let(...) 階段中定義的名稱相同,系統會覆寫先前的變數。這可用於在管道進展時更新暫時狀態。

子管道中參照的變數會遵循許多程式設計語言中的詞彙範圍規則,並參照最接近 (父項) 管道定義的同名變數。

與「add_fields(...)」比較

let(...) 階段的行為與 add_fields(...) 階段類似,但會將值指派給變數,而不是在文件中新增欄位。