はじめに
チャットアプリを作る場合、Socket.ioなどで自前で実装することが多かったのですが、今回、Realtime Databaseを使って実装してみたので、その覚書です。フレームワークは今回はFlutterを用いていますが、PWA(Progressive Web Apps)で作る場合でも、相互にデータをやりとりできるため、非常に便利です。今回はアプリと、Webの方では要件からVanillaJSでcallする必要があったのでそれぞれからの呼び出しをメモしておきます。
制限事項
(プライシング)
https://firebase.google.com/pricing/?hl=ja
RealTimeDatabaseは無償の場合は、同時接続=100、容量=1GB、転送量=10GBが最大。
課金に移行した場合でも、容量=$5/GB、転送量=$1/GBかかってくるので
リアルタイム性が必要ないものは、Firestoreに逃すなどが必要かもしれません。
とはいえ、Firestoreの方は、書き込み = $0.18/10 万 / 読み込み =$0.06/10 万 / 削除 = $0.02/10 万と、リクエス数に応じて金額が上がるので、頻繁に書き込みがあるか、データの容量が多いのか、その辺りでどちらをどう使うか、判断が必要そうな感じ。
(Node-redなどを使って、Socket.ioなどで実装しmonogoDBなどでstoreするなど、
金額を考えた場合はもっと他の選択肢もあるかもしれませんがこちらは試算していません。。)
前提
FirebaseSDKのimportまでは済んでいる状態
実装
Flutter(App)
FirebaseのRealtimeDatabaseでは下記のような構造を想定します。

まずは、Appのデータ送信部分。gidは、この事例でいく9TrzkKitHwHcO0x350jl というグループIDを示しており、
例えばチャットルームIDなどの識別子として利用します。今回はその下に、messagesと言うディレクトリをほり、そこにdataを追記(push)していく構造を取っています。
Firebase 参照に新しい子が追加されると、そのたびに push() メソッドは一意の ID を生成し、さらに、これらは時系列に並ぶようになっています。
void sendData(String text) {
Map data;
data = {"name": "user1", "message":"hello"};
database.reference().child(widget.gid + '/messages').push().set(data);
}
次にデータの取得部分です。Realtime Databaseの場合、追加、更新、削除の時に
自動で描画して欲しいため、FirebaseAnimatedListを用いています。これを行うと、いわゆるチャットの挙動になります。
Expanded(
child: FirebaseAnimatedList(
query: database.reference().child(widget.gid + '/messages'),
itemBuilder: (_, DataSnapshot snapshot,
Animation<double> animation, int index) {
data = snapshot.value;
return message(data['name'], data['message']);
})),
VanillaJS(Web)
JavaScriptの場合は、下記のようにsendします。
var database = firebase.database().ref(_gid).child('messages');
database.push({
name: 'user2',
message: 'hello'
});
var database = firebase.database().ref(_gid).child('messages');
database.on('child_added', function (snapshot) {
var msg = snapshot.val();
$("#message_list").prepend(formatHtml(msg.name,msg.message));
});