Let

説明

パイプラインの後続のステージで参照できる一時変数を定義します。

let(...) ステージで作成された変数は、後のステージでフィールドに明示的に割り当てられない限り(add_fields(...)select(...) を使用するなど)、最終結果には含まれません。これにより、出力ドキュメントを煩雑にすることなく、複雑なロジックを再利用可能な小さなコンポーネントに分割して簡素化できます。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(...) など)が最初に発生するまで、ステージ間でアクセス可能です。複数のドキュメントを「マージ」するステージでは、変数参照を後で使用することはできません。前のステージの結果をマージすると、変数の値が 1 つではなくなるためです。

行うこと: ドキュメントのフィールドをフィルタした後で、変数を参照します。

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(...) ステージと同様に動作しますが、ドキュメントにフィールドを追加するのではなく、変数に値を割り当てます。