メインコンテンツまでスキップ

トリガー

データベースの変更に応じてバックエンド関数を自動的に実行します。

トリガーを使う理由

データが変更されたときに反応する必要があります。新規ユーザー登録時に通知を送信したり、商品が変更されたら検索インデックスを更新したり、レコードが削除されたら監査ログ(audit trail)を記録したり、などです。

トリガーがない場合、このロジックをデータを書き込むあらゆる場所に分散して書くか、データベースの変更をポーリングして検知する必要があります。トリガーを使えば、監視するコレクションを宣言するだけで、Squid があなたの関数を自動的に呼び出します。

// Backend: runs automatically when a document changes
@trigger('onNewOrder', 'orders')
async handleNewOrder(request: TriggerRequest<Order>): Promise<void> {
if (request.mutationType === 'insert') {
await this.sendOrderConfirmation(request.docAfter);
}
}

ポーリング不要。ロジックの重複なし。データが変更されたまさにそのタイミングでコードが実行されます。

概要

トリガーは、データベースコレクション内のドキュメントが insert / update / delete されたときに自動的に実行されるバックエンド関数です。mutation(変更)がコミットされた後に実行されるため、リアクティブなワークフローを構築するための信頼できる手段になります。

トリガーを使うべきとき

ユースケース推奨
データベース変更に自動で反応する✅ Trigger
クライアントから関数を呼び出すExecutables を使用
スケジュールでコードを実行するSchedulers を使用
外部サービス向けに HTTP endpoint を公開するWebhooks を使用

仕組み

  1. SquidService を継承したクラス内のメソッドに @trigger を付与する
  2. Squid が deploy 時にトリガーを登録する
  3. 指定されたコレクションのドキュメントが insert / update / delete されると、Squid がその関数を呼び出す
  4. 関数は TriggerRequest を受け取り、mutation type、変更前後のドキュメント、ドキュメント ID が渡される

クイックスタート

前提条件

  • squid init-backend で初期化済みの Squid backend project
  • @squidcloud/backend パッケージがインストールされていること

Step 1: トリガー関数を作成する

SquidService を継承する service クラスを作成し、トリガーを追加します。

Backend code
import { SquidService, trigger, TriggerRequest } from '@squidcloud/backend';

export class ExampleService extends SquidService {
@trigger('userChange', 'users')
async handleUserChange(request: TriggerRequest): Promise<void> {
console.log(`User ${request.docId} was ${request.mutationType}d`);
console.log('Before:', request.docBefore);
console.log('After:', request.docAfter);
}
}

Step 2: service をエクスポートする

service の index ファイルからエクスポートされていることを確認します。

service/index.ts
export * from './example-service';

Step 3: バックエンドを起動またはデプロイする

ローカル開発では、Squid CLI を使ってバックエンドをローカル実行します。

squid start

クラウドにデプロイするには、deploying your backend を参照してください。

これで users コレクションのドキュメントが insert / update / delete されるたびに、トリガーが自動的に発火します。

コアコンセプト

@trigger デコレーター

@trigger デコレーターには 2 つの形式があります: 位置引数(positional parameters)と options object です。

位置引数(positional parameters):

Backend code
@trigger('userChange', 'users')              // id, collection (uses built-in DB)
@trigger('userChange', 'users', 'myDatabase') // id, collection, connectorId
パラメータ説明
idstringこのトリガーの一意な識別子
collectionNamestring監視するコレクション名
integrationId?stringconnector ID。デフォルトは built-in database

Options object:

Backend code
@trigger({ collection: 'users', mutationTypes: ['insert', 'update'] })
プロパティ説明
id?string一意な識別子。省略時は ClassName.FunctionName がデフォルト
collectionstring監視するコレクション名
integrationId?stringconnector ID。デフォルトは built-in database
mutationTypes?MutationType[]どの mutation type で関数を起動するかをフィルタリング。省略時はすべての mutation で起動

TriggerRequest

トリガー関数に渡される TriggerRequest<T> オブジェクトには、変更に関する詳細が含まれます。

プロパティ説明
docIdstring | Record<string, any>ドキュメント ID(単一フィールドのキーは string、複合キーは object)
collectionNamestring影響を受けたコレクション名
integrationIdstring影響を受けたデータベースの connector ID
mutationTypeMutationTypemutation type: 'insert''update''delete'
docBefore?Tmutation 前のドキュメント状態。updatedelete で利用可能
docAfter?Tmutation 後のドキュメント状態。insertupdate で利用可能

ジェネリック型パラメータ T により、ドキュメントデータを型付けできます。

Backend code
interface User {
id: string;
name: string;
email: string;
}

@trigger('userChange', 'users')
async handleUserChange(request: TriggerRequest<User>): Promise<void> {
// request.docAfter is typed as User | undefined
const user = request.docAfter;
if (user) {
console.log(user.name); // type-safe access
}
}

Mutation types

トリガーは 3 種類の mutation に反応します。

Mutation TypedocBeforedocAfter説明
'insert'undefinedPresent新しいドキュメントが作成された
'update'PresentPresent既存のドキュメントが変更された
'delete'Presentundefinedドキュメントが削除された

mutation type によるフィルタリング

特定の mutation type のみで発火させたい場合は、options object 形式を使います。insert / update / delete で別々のロジックが必要なときに便利です。

Backend code
import { SquidService, trigger, TriggerRequest } from '@squidcloud/backend';

export class OrderService extends SquidService {
@trigger({ collection: 'orders', mutationTypes: ['insert'] })
async onNewOrder(request: TriggerRequest): Promise<void> {
// Only runs on insert
await this.sendOrderConfirmation(request.docAfter);
}

@trigger({ collection: 'orders', mutationTypes: ['update'] })
async onOrderUpdate(request: TriggerRequest): Promise<void> {
// Only runs on update
await this.notifyOrderStatusChange(request.docBefore, request.docAfter);
}

@trigger({ collection: 'orders', mutationTypes: ['delete'] })
async onOrderCancelled(request: TriggerRequest): Promise<void> {
// Only runs on delete
await this.processRefund(request.docBefore);
}
}

外部データベース connector を使う

デフォルトでは、トリガーは built-in database を監視します。外部データベース connector 内のコレクションを監視するには、connector ID を指定してください。

Backend code
// Positional form
@trigger('userSync', 'users', 'myPostgresDb')

// Options object form
@trigger({ collection: 'users', integrationId: 'myPostgresDb' })

トリガーは、PostgreSQL、MySQL、MongoDB など、mutation をサポートする任意の database connector で動作します。

Squid client を使う

トリガー内から this.squid を使って他の Squid services にアクセスできます。これにより、client SDK で利用できるのと同じ Database 操作が使えます。

Backend code
@trigger('auditLog', 'orders')
async logOrderChange(request: TriggerRequest): Promise<void> {
const auditCollection = this.squid.collection('audit-log');
await auditCollection.doc().insert({
collection: request.collectionName,
docId: request.docId,
mutationType: request.mutationType,
timestamp: new Date(),
before: request.docBefore,
after: request.docAfter,
});
}

エラーハンドリング

トリガーは mutation のコミット後に実行されます。トリガーがエラーを throw しても、元の mutation はロールバックされません。変更情報を失わないように、トリガー側で適切にエラーを処理してください。

Backend code
@trigger('processChange', 'payments')
async handlePaymentChange(request: TriggerRequest): Promise<void> {
try {
await this.processPaymentUpdate(request);
} catch (error) {
console.error(`Trigger failed for doc ${request.docId}:`, error);
// Log the failure for manual review
await this.squid.collection('failed-triggers').doc().insert({
docId: request.docId,
mutationType: request.mutationType,
error: String(error),
timestamp: new Date(),
});
}
}

ベストプラクティス

  1. トリガーは高速に保つ。 トリガーは各 mutation の後に非同期で実行されます。時間のかかる処理は後続の変更の処理を遅らせます。重い処理は、トリガーで queue 用のコレクションに書き込み、別途それを処理してください。

  2. エラーを丁寧に処理する。 トリガーのエラーは元の mutation をロールバックしないため、失敗をログに残し、重要な処理であればリトライ機構を検討してください。

  3. mutation type フィルタリングを使う。 特定の操作にのみロジックを適用したい場合は mutationTypes オプションを使い、不要なトリガー実行を避けてください。

  4. 循環トリガーを避ける。 トリガーが監視対象と同じコレクションに書き込むと、ループして自分自身を発火させます。別コレクションに書き込むか、mutation type フィルタリングでサイクルを防いでください。

  5. TriggerRequest を型付けする。 ドキュメントデータへの型安全なアクセスのために、ジェネリックパラメータ(TriggerRequest<MyType>)を使ってください。

コード例

新規レコード作成時に通知を送る

Backend code
import { SquidService, trigger, TriggerRequest } from '@squidcloud/backend';

interface User {
id: string;
name: string;
email: string;
}

export class NotificationService extends SquidService {
@trigger({ collection: 'users', mutationTypes: ['insert'] })
async welcomeNewUser(request: TriggerRequest<User>): Promise<void> {
const user = request.docAfter;
if (!user) return;

await this.squid.collection('notifications').doc().insert({
userId: user.id,
message: `Welcome, ${user.name}!`,
createdAt: new Date(),
});
}
}

派生コレクション(derived collection)を維持する

Backend code
import { SquidService, trigger, TriggerRequest } from '@squidcloud/backend';

interface Product {
id: string;
name: string;
price: number;
category: string;
}

export class AnalyticsService extends SquidService {
@trigger('productSync', 'products')
async syncProductStats(request: TriggerRequest<Product>): Promise<void> {
const statsCollection = this.squid.collection('category-stats');

if (request.mutationType === 'insert') {
const product = request.docAfter!;
const statsDoc = statsCollection.doc(product.category);
const stats = await statsDoc.snapshot();
await statsDoc.insert({
category: product.category,
count: (stats?.count ?? 0) + 1,
});
}

if (request.mutationType === 'delete') {
const product = request.docBefore!;
const statsDoc = statsCollection.doc(product.category);
const stats = await statsDoc.snapshot();
if (stats) {
await statsDoc.update({ count: Math.max(0, stats.count - 1) });
}
}
}
}

関連項目

  • Executables - クライアントからバックエンド関数を呼び出す
  • Schedulers - スケジュールに従ってコードを実行する
  • Webhooks - HTTP endpoints を公開する
  • Rate and quota limiting - バックエンド関数を保護する
  • API reference - trigger デコレーターの完全な API ドキュメント