データの追加
楽観的更新(optimistic updates)による高速で応答性の高いユーザー体験。
なぜ Mutations を使うのか
データベース内で新しいレコードを作成したり、既存のレコードを更新したりする必要があります。Squid Client SDK は、クライアント側で変更を楽観的に適用して UI に即時フィードバックを返し、その後サーバーと非同期に同期する insert と update の操作を提供します。
クイックスタート
// Insert a new document
await squid.collection<User>('users').doc('user_1').insert({
name: 'Alice',
email: 'alice@example.com',
});
概要
transaction 内で実行されない限り、すべての insert と update は Promise を返し、その mutation がサーバーに適用された時点で resolve します。
insert と update はローカルで楽観的に適用され、クライアントに即座に反映されます。変更内容はその後、整合性がありクリーンなデータ状態を保証するために、サーバーへ非同期に送信されます。
書き込み mutation には insert、update、setInPath の 3 種類があります。いずれも document reference に対して実行されます。
コアコンセプト
Insert
Insert は新しいドキュメントを作成するために使用します。
コレクションに新しいドキュメントを insert するには、DocumentReference に対して insert メソッドを呼び出し、
新しいドキュメントデータを引数として渡します。
try {
await squid.collection<User>('users').doc('new_user_id').insert({
name: 'John Doe',
email: 'johndoe@example.com',
});
console.log('User added successfully');
} catch (error) {
console.error(`Failed to add user ${error}`);
}
バックエンドの security rules により、各 mutation を誰が実行できるかを粒度高く制御できます。これらのルールは MutationContext をパラメータとして受け取り、変更前後のドキュメントの snapshot など、mutation に必要な詳細をすべて含みます。security rules の詳細を読んで、書き方を理解してください。
Insert many
insertMany メソッドは、複数ドキュメントを一度に効率よく insert および/または update するために使用します。次の例では、新しい user ドキュメントの配列を追加します。
const newDocuments = [
{
id: 'new_user_id1',
data: {
name: 'John Doe',
email: 'johndoe@example.com',
},
},
{
id: 'new_user_id2',
data: {
name: 'Jan Smith',
email: 'jansmith@example.com',
},
},
];
try {
await squid.collection<User>('users').insertMany(newDocuments);
console.log('Users added successfully');
} catch (error) {
console.error(`Failed to add users ${error}`);
}
Update
ドキュメントを update するには、DocumentReference に対して update メソッドを呼び出し、
部分的な更新データを含むオブジェクトを引数として渡します。
try {
await squid
.collection<User>('users')
.doc('existing_user_id')
.update({ email: 'new_email@example.com' });
console.log('User updated successfully');
} catch (error) {
console.error(`Failed to update user ${error}`);
}
Set in Path
DocumentReference に対して setInPath メソッドを呼び出し、プロパティへの path と新しい値を引数として渡すことで、ドキュメントの特定のプロパティだけを update することもできます。path でネストしたプロパティを指定するには、ドット記法を使用します。
const userRef = squid.collection<User>('users').doc('existing_user_id');
try {
await userRef.setInPath('address.street', 'Main');
console.log('Updated successfully');
} catch (error) {
console.error(`Failed to update user ${error}`);
}
エラーハンドリング
| Error | Cause | Solution |
|---|---|---|
| Security rule rejection | mutation が security rules によりブロックされた | ユーザーがそのコレクションに対する書き込み権限を持つことを確認する |
| Document already exists | 一部の connector types で、すでに存在する document ID に対して insert を呼び出している | 既存ドキュメントには update を使うか、ユニークな ID を使用する |
| Invalid data shape | insert するデータがコレクション schema と一致しない | データオブジェクトが期待される schema と型に一致することを確認する |
| Network error | mutation の確認のためにサーバーへ到達できなかった | 楽観的更新はロールバックされるため、操作をリトライする |
ベストプラクティス
-
部分的な変更には
update()を使用する:ドキュメント全体を再 insert するのではなく、変更されたフィールドのみを送信します。 -
深いネストの更新には
setInPath()を使用する:ドキュメントの他の部分に触れず、単一のネストフィールドだけを変更します。Client code// Update only the city without affecting other address fields
await userRef.setInPath('address.city', 'New York'); -
バルク操作には
insertMany()を使用する:サーバーとの往復回数(round trips)を減らします。 -
複数ドキュメントにまたがる atomicity が必要な場合は、関連する mutation を transaction でラップする。
-
mutation のエラーを処理する:クライアント側のバリデーションを通過しても、security rules や schema チェックでサーバーにより変更が拒否される場合があります。