Cloud Firestore トリガー

Cloud Functions を使用すると、クライアント コードを更新することなく、Cloud Firestore 内のイベントを処理できます。Cloud Firestore の変更は、DocumentSnapshot インターフェースまたは Admin SDK で行います。

一般的なライフサイクルの場合、Cloud Firestore の関数は以下のように動作します。

  1. 特定のドキュメントに変更が加えられるのを待ちます。
  2. イベントが発生するとトリガーされ、そのタスクを実行します(ユースケースについては、Cloud Functions で可能な処理 をご覧ください)。
  3. 指定されたドキュメントに保存されているデータのスナップショットを含むデータ オブジェクトを受け取ります。onWrite イベントまたは onUpdate イベントの場合、データ オブジェクトには、トリガーとなるイベントの前後のデータ状態を表す 2 つのスナップショットが含まれています。

Firestore インスタンスのロケーションと関数のロケーションとの距離によって、ネットワーク レイテンシが大幅に長くなる可能性があります。パフォーマンスを最適化するために、関数のロケーションは適切な場所に指定してください。

Cloud Firestore の関数をトリガーする

Cloud Functions for Firebase SDK は、特定のイベントのハンドラを作成できる functions.firestore オブジェクトをエクスポートします。

Cloud Firestore は、createupdatedeletewrite イベントをサポートしています。

イベントタイプ トリガー
onCreate ドキュメントが最初に書き込まれたときにトリガーされます。
onUpdate すでに存在するドキュメントの値が変更されたときにトリガーされます。
onDelete データを含むドキュメントが削除されたときにトリガーされます。
onWrite onCreateonUpdate または onDelete がトリガーされたときにトリガーされます。

プロジェクトを Cloud Functions for Firebase でまだ有効にしていない場合には、はじめに: 最初の関数の記述とデプロイを参照して、Cloud Functions for Firebase プロジェクトを構成します。

特定のドキュメントが変更されたときに関数をトリガーする

特定のドキュメントが変更されたときにイベントをトリガーするには、次の関数を使用します。

Node.js

// Listen for any change on document `marie` in collection `users`
exports.myFunctionName = functions.firestore
    .document('users/marie').onWrite((change, context) => {
      // ... Your code here
    });

新しいドキュメントが作成されたときに関数をトリガーする

onCreate() ハンドラでワイルドカードを使用すると、コレクションで新しいドキュメントが作成されるたびに関数をトリガーできます。この例の関数は、新しいユーザー プロフィールが追加されるたびに createUser を呼び出します。

Node.js

exports.createUser = functions.firestore
    .document('users/{userId}')
    .onCreate((snap, context) => {
      // Get an object representing the document
      // e.g. {'name': 'Marie', 'age': 66}
      const newValue = snap.data();

      // access a particular field as you would any JS property
      const name = newValue.name;

      // perform desired operations ...
    });

ドキュメントが更新されたときに関数をトリガーする

onUpdate() 関数でワイルドカードを使用すると、ドキュメントが更新されたときに関数をトリガーできます。この例の関数は、ユーザーがプロフィールを変更すると、updateUser を呼び出します。

Node.js

exports.updateUser = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {
      // Get an object representing the document
      // e.g. {'name': 'Marie', 'age': 66}
      const newValue = change.after.data();

      // ...or the previous value before this update
      const previousValue = change.before.data();

      // access a particular field as you would any JS property
      const name = newValue.name;

      // perform desired operations ...
    });

ドキュメントが削除されたときに関数をトリガーする

onDelete() 関数でワイルドカードを使用すると、ドキュメントが削除されたときに関数をトリガーできます。次の例の関数は、ユーザーがユーザー プロフィールを削除すると deleteUser を呼び出します。

Node.js

exports.deleteUser = functions.firestore
    .document('users/{userID}')
    .onDelete((snap, context) => {
      // Get an object representing the document prior to deletion
      // e.g. {'name': 'Marie', 'age': 66}
      const deletedValue = snap.data();

      // perform desired operations ...
    });

ドキュメントが変更されたときに関数をトリガーする

発生するイベントの種類に関係なく、Cloud Firestore ドキュメントのすべての変更をリッスンするには、onWrite() 関数でワイルドカードを使用します。次の例の関数は、ユーザーの作成、更新または削除が発生したときに modifyUser を呼び出します。

Node.js

exports.modifyUser = functions.firestore
    .document('users/{userID}')
    .onWrite((change, context) => {
      // Get an object with the current document value.
      // If the document does not exist, it has been deleted.
      const document = change.after.exists ? change.after.data() : null;

      // Get an object with the previous document value (for update or delete)
      const oldDocument = change.before.data();

      // perform desired operations ...
    });

イベントデータを処理する

データの読み取り

関数がトリガーされた後、更新済みのドキュメントのデータを取得する場合や、更新前のデータを取得する場合があります。更新前のデータは、更新前のドキュメントのスナップショットを含む change.before.data() を使用して取得できます。同様に、change.after.data() には更新後のドキュメントのスナップショットの状態が含まれます。

Node.js

exports.updateUser = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {
      // Get an object representing the current document
      const newValue = change.after.data();

      // ...or the previous value before this update
      const previousValue = change.before.data();
    });

プロパティには、他のオブジェクトの場合と同様にアクセスできます。または、get 関数を使用して特定のフィールドにアクセスすることもできます。

Node.js

// Fetch data using standard accessors
const age = snap.data().age;
const name = snap.data()['name'];

// Fetch data using built in accessor
const experience = snap.get('experience');

データの書き込み

それぞれの関数呼び出しは、Cloud Firestore データベースの特定のドキュメントに関連付けられています。このドキュメントには、関数に返されたスナップショットの ref プロパティの DocumentReference でアクセスできます。

この DocumentReferenceCloud Firestore Node.js SDK で提供され、update()set()remove() などのメソッドが含まれているので、関数をトリガーしたドキュメントを簡単に変更できます。

Node.js

// Listen for updates to any `user` document.
exports.countNameChanges = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {
      // Retrieve the current and previous value
      const data = change.after.data();
      const previousData = change.before.data();

      // We'll only update if the name has changed.
      // This is crucial to prevent infinite loops.
      if (data.name == previousData.name) return null;

      // Retrieve the current count of name changes
      let count = data.name_change_count;
      if (!count) {
        count = 0;
      }

      // Then return a promise of a set operation to update the count
      return change.after.ref.set({
        name_change_count: count + 1
      }, {merge: true});
    });

ワイルドカードとパラメータの使用

イベント トリガーを関連付けるドキュメントがわからない場合には、ドキュメント ID の代わりに {wildcard} を使用できます。

Node.js

// Listen for changes in all documents and all sub-collections
exports.useWildcard = functions.firestore
    .document('users/{userId}')
    .onWrite((change, context) => {
      // If we set `/users/marie` to {name: "marie"} then
      // context.params.userId == "marie"
      // ... and ...
      // change.after.data() == {name: "Marie"}
    });

この例では、users にあるドキュメントの任意のフィールドが変更されると、userId というワイルドカードと照合されます。

users のドキュメントにサブコレクションがあり、サブコレクションのいずれかのドキュメントのフィールドが変更された場合、userId ワイルドカードはトリガーされません

ワイルドカードに一致した部分がドキュメント パスから抽出され、event.params に保存されます。明示的なコレクションまたはドキュメント ID に置き換えるワイルドカードは、必要な数だけ定義できます。

Node.js

// Listen for changes in all documents and all subcollections
exports.useMultipleWildcards = functions.firestore
    .document('users/{userId}/{messageCollectionId}/{messageId}')
    .onWrite((change, context) => {
      // If we set `/users/marie/incoming_messages/134` to {body: "Hello"} then
      // context.params.userId == "marie";
      // context.params.messageCollectionId == "incoming_messages";
      // context.params.messageId == "134";
      // ... and ...
      // change.after.data() == {body: "Hello"}
    });

制約と保証

アプリケーションを開発する場合には、Cloud Firestore が現在ベータ版であること、つまり予期しない動作が起きる可能性があるという点に注意してください。

次のような制約があります。

  • Cloud Firestore のデータが変更されてから関数がトリガーされるまで 10 秒ほどかかる場合があります。
  • すべてのバックグラウンド関数と同様に、イベントの順序は保証されていません。1 つのイベントで Cloud Functions が複数回呼び出される可能性があるため、関数で高い精度が求められる場合には、関数の書き込みをべき等にする必要があります。

フィードバックを送信...

ご不明な点がありましたら、Google のサポートページをご覧ください。