Developersをフォローする

Firebaseでデータを更新する

インフラ

業務でFirebaseを使いはじめて約半年が経過し、大体全貌が見えてきたので今回取り上げてみました。
本記事では以下についてまとめています。

  1. Firebaseの概要
  2. Firebaseのデータベース(Firestore)について
  3. Firestoreを更新するための方法について

Firebaseとは

Firebaseとはサーバーの開発が不要で、フロント側だけでアプリ開発ができるクラウドサービス」です。

Firebaseの構成は、上記の図のようにFirebaseProjectが最上位にあり、その配下にFirebaseAppsというアプリ(Apple,Android,Webアプリ)を登録できます。
アプリは複数登録することが可能で、すべてのアプリでバックエンド(Resources and Services)を共有できます。

Firebaseプロジェクトの実態とは?

Firebaseプロジェクトの実態はGoogleCloudプロジェクトです。
Google Cloudとは、その名のとおり、Googleが提供するクラウドサービスを指します。AWSやAzureともよく比較されていますね。

Firebaseプロジェクトを作成する際に自動でGoogleCloudプロジェクトも作成されますが、先にGooleCloudプロジェクトを作成しあとからFirebaseプロジェクトを追加することもできます。
Firebaseのバックエンドは、Google Cloudプロジェクトが提供するデータ、コード、構成、サービスの仮想コンテナと考えることができます。
そのため、FirebaseはFirebaseのコンソールからでも、GoogleCloudのコンソールからでも操作できるようになっています。

また、APIもFirebaseとGoogleCloudのものが両方使えます。

Cloud Firestoreの更新方法について

CloudFirestoreとは、前述したとおりFirebaseのデータベースに当たります。

CloudFirestoreを更新する方法は大きく分けて2つあります。

  1. webアプリケーション(フロント)から更新する
  2. CloudFunctionを使って更新する

それぞれについて詳しく見ていきます。

webアプリケーション(フロント)から更新する

フロントから更新するためには、JavaScript モジュール形式を使用する Firebase JS SDK というライブラリを使用します。

Firebase JS SDKの記述方法

1.はじめにFirebaseライブラリをnpm installします。

npm install firebase

2.アプリでFirebaseを作成し、Firebase アプリオブジェクトを作成します。

import { initializeApp } from 'firebase/app';

// TODO: Replace the following with your app's Firebase project configuration
const firebaseConfig = {
  //...
};

const app = initializeApp(firebaseConfig);

3.firebaseにアクセスします。

以下のコードは、Firestoreのライブラリをインポートしています。
Firestoreのcitiesというcollectionに”LA”というドキュメントを追加しています。
(RDBSでいうとcollection=テーブル、ドキュメント=レコード)

import { getFirestore, collection, getDocs } from 'firebase/firestore/lite';

const db = getFirestore(app);

await setDoc(doc(db, "cities", "LA"), {
  name: "Los Angeles",
  state: "CA",
  country: "USA"
});

その他の記述方法

フロントから更新する際は、reactを使っている場合はreact-redux-firebaseといったライブラリも使うことができます。上記よりもかなりシンプルに書けます。

CloudFunctionで更新する

CloudFunctionとは

CloudFunctionとは、サーバーレスでイベント駆動型のアプリケーションを作成するためのサービスです。
開発者は、トリガーとなるイベントまたは関数名と、関数の内容をNode.jsでコーディングして、ビルドをすることによってその関数がクラウド上で実行できるようになります。

CloudFunctionでのフロント側と同様にfirestoreのデータの更新等を行えますが、フロント側とは使用するライブラリが異なり、
firebaseのインスタンス化・接続にfirebase-admin、functionの設定にfirebase-functionというライブラリを使用します。

CloudFunctionでできること

CloudFunctionで実行する関数には2種類あります。

  1. webアプリケーションから、関数を直接呼び出す
  2. トリガーされたイベントに応じて、関数を自動で実行する

1, 2のコードの書き方は同様ですが、定義の仕方が違うのでそれぞれ見ていきます。

webアプリケーションから関数を呼び出す

1.関数createCityをonCallで定義します。

exports.createCity= functions.https.onCall((data, context) => {
  // ...
});

2. デプロイします。

firebase deploy --only functions:addMessage

3.呼び出し処理をフロント側に記載します。

import * as admin from 'firebase-admin';
import * as f from 'firebase-functions';

// firebaseをインスタンス化
const app = admin.initializeApp();
const firestore = app.firestore();
// firestore
const functions = getFunctions();
const createCity= httpsCallable(functions, 'createCity');
createCity({ cities:City })
  .then((result) => {
     const db = firestoreClient;
    // citiesを作成する処理
     await db
          .collection("cities")
          .doc("LA")
          .set({name: "Los Angeles",state: "CA",country: "USA" 
      });
  });

トリガーされたイベントに応じて、関数を自動で実行する

特定のドキュメントへの変更をトリガーに、関数を実行することができます。

トリガーの種類は以下の4つになります。

onCreateドキュメントが初めて書き込まれたときにトリガーされます。
onUpdateドキュメントがすでに存在し、値が変更されたときにトリガーされます。
onDeleteデータを含むドキュメントが削除されたときにトリガーされます。
onWriteonCreate 、 onUpdateまたはonDeleteがトリガーされたときにトリガーされます。

Cloud Firestore トリガーを定義するには、ドキュメント パスとイベント タイプを指定します。
1. でawait setDoc(doc(db, “cities”, “LA”)を実行した場合に、自動で動く関数は以下のように定義します。

const functions = require('firebase-functions');

exports.myFunction = functions.firestore
  .document('cities/LA')
  .onCreate((change, context) => { /* ... */ });

Cloud Fuctionの注意点

CloudFunctionは関数の実行時間が一定時間を超えるとタイムアウトしてしまいます。
また、呼び出し回数によって料金がかかります。(2 百万/月までは無料)
時間がかかりそうな処理を実装する際は、タイムアウトにならないよう工夫する必要があります。
ちなみにfirestoreの読み取りにもコストがかかります。

まとめ

後半からデータの更新方法というより関数の実行の仕方になってしまい、若干話題がそれてしまったのですが、実際のプロジェクトではデータを更新する際の処理の複雑さや、連動してデータを更新する必要があるかによって使い分けています。
また、便宜上「データを更新する」という処理に着目して記載しましたが、実際にはCloudFunctionでは様々な処理を行うことができます。

最後に、どのように使い分けているかと、これまでの実務で学んだfirebaseで気を付けたい点についてまとめて終わります。

結局どう使い分けるのか?

  1. フロントから更新する場合 → 特に連動するデータもなく、更新する値がフロントのみで完結できる場合
  2. フロントからCloudFunctionを呼び出す場合 → データを複製する処理(firestoreの値を検索して登録したい場合)、メールの送信などを行う場合
  3. イベントをトリガーにCloudFunctionを呼び出す場合 → 通知機能など(replyドキュメントが作成されたら、notificationドキュメントを作成)

気を付けたいこと

  1. 同じデータを更新するという処理でも、フロント側とCloudFunction側で使うライブラリが異なる上に、できることも異なる
  2. firebase=GoogleCloudという認識がないと、ライブラリを確認するときに惑わされることがある
  3. CloudFunctionにはタイムアウトの制限、課金があるため、余計な読み取りを行わない・関数実行時のデータ容量チェック等が必要