kaz.dev

Firebase(Cloud Firestore) を使ってみる

tag: firebase, firestore


はじめに

前から使ってみたいけど、素振りをするタイミングがなかったなのでやっていく





準備

今回は新規プロジェクト(名前はlerning-xxxxとした)を作成し、テストモードで触っていく
ロケーションはなんとなくasia-northeast2(大阪)にした

Cloud Firestore のロケーション | Firebase





Credentialの入手

プロジェクトの設定 > サービスアカウント > 新しい秘密鍵の入手 から
learning-xxx-firebase-adminsdk-yyyy-zzzz.json を入手した





データの投入

初期データとして users というコレクションを作成、その中にランダムなIDを付与した、name: string, age: numberというデータを追加した





データの取得

先ほど投入したデータを取得してみる

$ yarn init -y
$ yarn add firebase-admin
$ yarn add -D typescript ts-node
import admin from "firebase-admin"
import type { firestore } from "firebase-admin/lib/firestore"

interface User {
  name: string;
  age: number;
}

async function main() {
  const app = admin.initializeApp({
    credential: admin.credential.cert("./learning-xxxx-firebase-adminsdk-yyyy-zzzz.json")
  });

  const db = app.firestore()

  const users = db.collection("users") as firestore.CollectionReference<User>
  const data = (await users.get()).docs.map(doc => {
    return {
      ...doc.data(),
      createTime: doc.createTime,
      updateTime: doc.updateTime,
    };
  });

  console.log(data);
}

main();

これでこんなデータが取れる

[
  {
    age: 10,
    name: 'sam',
    createTime: Timestamp { _seconds: 1629609782, _nanoseconds: 517270000 },
    updateTime: Timestamp { _seconds: 1629609782, _nanoseconds: 517270000 }
  }
]




データの追加

{name: "bob", age: 16}というデータを追加してみる

async function add(user: User) {
  const users = db.collection("users") as firestore.CollectionReference<User>;
  const result = await users.add(user);
  console.log(result);
}

add({name: "bob", age: 16});

ブラウザ上で確認すると追加されていた

一応先ほどのコードで取得できるか確認してみる

[
  {
    age: 10,
    name: 'sam',
    createTime: Timestamp { _seconds: 1629609782, _nanoseconds: 517270000 },
    updateTime: Timestamp { _seconds: 1629609782, _nanoseconds: 517270000 }
  },
  {
    name: 'bob',
    age: 16,
    createTime: Timestamp { _seconds: 1629611977, _nanoseconds: 895093000 },
    updateTime: Timestamp { _seconds: 1629611977, _nanoseconds: 895093000 }
  }
]

このように問題なく取得できた





データの削除

最初に追加していたsamを削除する

async function del(id: string) {
  const users = db.collection("users") as firestore.CollectionReference<User>;
  const result = await users.doc(id).delete()
  console.log(result);
}

del("sam's id")

(雰囲気で書けた)

追加同様に確認すると削除されていることが確認できた





データの更新

bobの年齢を22歳にする

async function updateAge(id: string, age: User["age"]) {
  const users = db.collection("users") as firestore.CollectionReference<User>;
  const result = await users.doc(id).update({ age });
  console.log(result);
}

updateAge("bob's id", 22);

年齢だけ更新したいので年齢のフィールドだけ渡して、確認したら成功していた
簡単すぎて感動した





小休憩

CRUDが一瞬でできるのですごい便利&楽
ここまでは普通のRDBと同じなので、休憩したらもう少し色々探ってみる





ドキュメントを一通り読む

Cloud Firestore | Firebaseを読む





Cloud Firestore について理解する

データモデル

合ってるかわからないがRDBとの対応表を書いておく

Firestore RDB
コレクション テーブル
ドキュメント レコード

ドキュメントにコレクションを生やせることもできるので、実際は違うと思うが大まかな認識としては問題ないはず





データの追加と管理

データの追加

addsetについて

ドキュメントに有効な ID がなく、Cloud Firestore が ID を自動的に生成するように設定したほうが都合のよい場合もあります。この設定を行うには、add() を呼び出します。

.add(...).doc().set(...) は完全に同等なので、どちらでも使いやすい方を使うことができます。





サーバーのタイムスタンプ

ドキュメントのフィールドに、サーバーが更新を受信した時刻を追跡するサーバーのタイムスタンプを設定できます。

// Get the `FieldValue` object
const FieldValue = admin.firestore.FieldValue;

// Create a document reference
const docRef = db.collection('objects').doc('some-id');

// Update the timestamp field with the value from the server
const res = await docRef.update({
  timestamp: FieldValue.serverTimestamp()
});

ref: https://firebase.google.com/docs/firestore/manage-data/add-data#server_timestamp





utils

配列内の要素を更新する

配列フィールドがある場合は、arrayUnion() と arrayRemove() を使用して要素を追加および削除できます。arrayUnion() は要素を配列に追加しますが、追加されるのはまだ存在しない要素のみです。arrayRemove() は指定した各要素のすべてのインスタンスを削除します。

ref: https://firebase.google.com/docs/firestore/manage-data/add-data#update_elements_in_an_array

数値を増やす

数値フィールドの値は増減できます。increment オペレーションは、フィールドの現在の値を指定された分だけ増減します。フィールドが存在しない場合、または現在のフィールド値が数値でない場合、このオペレーションにより、指定した値がフィールドに設定されます。

ref: https://firebase.google.com/docs/firestore/manage-data/add-data#increment_a_numeric_value





データを読み取る

where

const citiesRef = db.collection('cities');
const snapshot = await citiesRef.where('capital', '==', true).get();
if (!snapshot.empty) {
  snapshot.forEach(doc => {
    console.log(doc.id, '=>', doc.data());
  });
}

more: Cloud Firestore で単純なクエリと複合クエリを実行する





必要があれば読む





さいごに

ざっくりとFirestoreを触ってみた

思ってたより色々できるし、簡単で、バックエンドエンジニアが必要なくなるという意見が出てくることも否めないなと思った

今回の素振りで適当なDBがほしい時にスッと使えそう

分散カウンタのページなどは学校や職場で投票システム作る時に良さそう