Firebaseの技術情報サイト

Firebaseの技術情報サイト

Firebase活用の為の技術情報サイトです

Firebaseデータベースのコレクションのリストの取得

Firebase データベースのコレクションのリストの取得

Firebase のデータベースを利用する際、特にサブコレクションを作成する場合、コレクションのリストが欲しい場合があります。この Firebase のデーターベースのコレクションの作成はちょっと面倒です。この記事ではコレクションのリストの取得の方法を紹介します。

目次
面倒なコレクションの取得
SDK による違い
実装例
バックエンドを使うと広がる実装オプション
まとめ

面倒なコレクションの取得

実は Firebase のデータベースのコレクションの取得はちょっと面倒です。通常の Firebase のフロントエンドのインターフェースでは、コレクションの一覧を取得する API はありません。

従って、フロントエンドのみの実装ではデータ構造を工夫して、コレクションのリストを間接的に取得できるような仕組みを作って置くような工夫が必要です。取得できない情報を別の形でデータベースに保存しておくようにします。 こうすることで、Firebase の制限を超えた実装が可能になります。

SDK による違い

Firebase にはフロントエンドとバックエンドでは違ったインターフェースを持っています。 Web アプリなどでフロントエンドの Web ブラウザで実行するコードの場合は、CDN(Contents Delivary Network)を HTML の中で指定する形や、NPM などで Firebase のモジュールをインストールします。

一方で、バックエンドで利用する場合には、「firebase admin SDK」を利用します。こちらの方は、いわゆる Node.js で利用するので、NPM で frebase admin SDK をインストールして利用します。

Firebase のインターフェースはどちらも非常に似ている部分が多いのですが、詳細のインターフェースはいろいろ違う部分があります。このコレクションの一覧を取得するインターフェースもその一つです。「admin」のインターフェースには「listCollections() 」が用意されていますが、通常のフロントエンドで利用されているインターフェースではサポートされていません。理由はよくわかりませんが、これがフロントエンドの Web ブラウザのコードではコレクションの一覧を取得できない理由です。

従って、直接 Firebase から実際のコレクションの一覧を取得するためには、Firebase admin SDK の「listCollections() 」を利用することができます。ただし、Firebase admin SDK は Node.js ベースの利用に限定されるので、同じ Javascript のコードでも Web ブラウザで実行することはできません。

この方法で、コレクションの一覧を取得する場合には以下の実装が必要で s

  • バックエンドのサービス(Firebase では Functions)が必要
  • フロントエンドとバックエンドのインターフェースを定義(REST API などを決める)
  • フロントエンドからはバックエンドのインターフェースを介してアクセス

という形になります。

実装例

では、バックエンドを活用した実装例を紹介します

バックエンドの実装例

バックエンドでは、REST API の定義は Excpress などのバックエンドのフレームワークを利用すると簡単です。 「/api/collections」という API を定義して「listCollections()」を使ってバックエンドで、指定したパスのサブコレクションのリストを取得して、応答するような処理にしています。

Firebase のホスティング機能を利用して、Functions を実現します。

import * as express from "express";
import * as firebase from "firebase-admin";
import * as functions from "firebase-functions";
import * as CONSTANT from "./constant";
const bodyParser = require("body-parser");
class BackendApp {
    public app: express.Express = express();
    private firebase: firebase.app.App = firebase.initializeApp({
        credential: firebase.credential.cert(
        path.join(__dirname, CONSTANT.SERVICE_ACCOUNT)
        ),
        databaseURL: CONSTANTS.FB_DB_URL,
    })
    constructor() {
        this.app.use(bodyParser.urlencoded({extended: false}));
        this.app.use(bodyParser.json());
        this.init();
    }
    init():void {
        this.app.get(
            "/api/collections",
            (req:express.Request, res:express:Response) => {
                const collection: string = req.body.collection;
                const docId: string = req.body.doc_id;
                this.firebase
                    .firestore()
                    .collection(collection)
                    .doc(docId)
                    .listCollections()
                    .then((collections:FirebaseFirestore.CollectionReference<FirebaseFirestore.DocumentData>) => {
                        const list: Array<string> = []
                        for (let i = 0 ; i < collections.length ; i++) {
                            list.push(collections[i].id)
                        }
                        res.end(JSON.stringify({success: true, collections: list }))
                }).catch((error: any) => {
                    res.end(JSON.stringify({success: false, collection: [], error: error})
                })
            }
        )
    }
}
const server = new BackendApp();
exports.app = functions.https.onRequest(server.app)

フロントエンドの実装例

フロントエンドでは、「/api/collections」の API を呼び出すとコレクションのリストを取得できます。 バックエンドからコレクションのリストが取得できない場合は、空の Array を返すようになっています。

function getEventContacts(payload: any): Promise<Array<string>> {
  return new Promise((resolve) => {
    const event_id = payload.id;
    console.log(event_id);
    const url = CONSTANT.BACKEND_URL + "/api/collections";
    axios
      .post(url, {
        uid: payload.uid as string,
        gid: payload.gid as string,
      })
      .then((res: AxiosResponse) => {
        if (res.data.success) {
          resolve(res.data.collections);
        } else {
          resolve([]);
        }
      })
      .catch((error: any) => {
        resolve([]);
      });
  });
}

バックエンドを使うと広がる実装オプション

Firebase のインターフェースは、非常によく設計されたインターフェースです。 大抵のことは、フロントエンドの Web ブラウザから行うことができますが、場合によってはこの Firebase のコレクションの一覧を取得するといった処理ができない場合もあります。

こうした場合、バックエンドの処理を組み合わせるとできることの範囲が広がります。フロントエンドでは許されていないような処理も、バックエンドではサポートされているという機能は少なくありません。

バックエンドの処理を導入できると可能になる事を考えると、実装の手段として、バックエンドの処理をサポートするというオプションがあると、役に立ちます。

まとめ

アプリの実装は、工夫と知識の拡張でできることが増えていきます。 利用しているモジュールや外部サービスがサポートしていないような機能が必要な場合の解決法は幾つかあります。

  • 工夫して処理を可能にする
  • 利用できる実装の範囲や知識・手法を広げる

多くの人が利用する機能の場合、大抵は公開されているモジュールなどを利用するとカバーできる場合が多くなっています。どんなモジュールが利用可能かの知識や経験を増やすというのは一つの方向です。

ただし、そうした外部のモジュールや拡張の機能を導入しなくても、ちょっとした工夫で問題を解決できる場合も少なくありません。今回紹介した、Firebase のコレクションの一覧はその良い例です。

Firebase admin SDK を使って、バックエンドのサービスを導入すれば簡単に解決できるのはこの記事で紹介した通りです。しかし、必要なコレクションのリストのコレクションを Firebase のデータベース上に作成して、「間接的」に取得する仕組みを自分で作って仕舞えば、バックエンドの導入は不要になります。ちょっとした工夫で大きな変更をなしに、フロントエンドでも似たような機能を実現できます。

プログラミングでは、大抵の場合、機能を実現する方法が一つではありません。幾つかの方法を挙げて、どの方法が現在開発している物に一番かを考えるとより良いアプリを作ることに繋がります。