Firebaseの続きです。前回はアプリを追加してFirebase CLIでFirebase Hostingにデプロイしました。今回はRealtime Databaseを設定してブラウザから直接CRUDしてみます。Firebaseドキュメントが膨大で自分的には結構難産でした。内容はいつもDB事始めでやっているビートルズメンバーCRUDですw それではいきましょう!
【目次】
※参考:前回記事
【Firebase】アプリを追加してFirebase CLIでFirebase Hostingにデプロイする - クモのようにコツコツと
※参考:Web開発環境についてのまとめ
qiita.com
前回のおさらい
Firebase CLIでFirebase Hostingにデプロイ
詳細は前回記事を参照
※参考:【Firebase】アプリを追加してFirebase CLIでFirebase Hostingにデプロイする - クモのようにコツコツと
これまで触ったDB
自分のDB初体験はこんな感じ。
- WordPressのMySQL:phpMyAdmin、AdminerなどのGUIツール
- MAMPのMySQL:ターミナル、Express
- JSON Server:ターミナル
- MongoDB:ターミナル、Express
- HerokuのPostgreSQL:ターミナル、Express
※参考:Web開発環境についてのまとめ(随時更新) - Qiita
※参考:Node.js / Expressを習得するためにやったことまとめ(随時更新) - Qiita
WordPress以外はまずターミナルからCRUD操作を試みた。その後サーバ側でExpressでAPIの設定をして、ブラウザ側からFetch APIでフォームデータを送ってCRUD操作した。
今回はFirebaseのRealtime Databaseを体験してみたい。HerokuのPostgreSQLに続きクラウドのDB。JSON形式のNoSQLのDBで、JSON Serverと似た感じがする。(Firebase にはMongoDBと似ているFirestoreもあるがこれはまた改めて…)
Realtime Databaseの設定
Realtime DatabaseもまずはターミナルからCRUD操作をすることから始めようと思ったのだが、ドキュメントで目立つのはこちらの「ウェブスタートガイド」。
※参考:Installation & Setup in JavaScript | Firebase Realtime Database
なんと、サーバ側のAPI設定も不要でブラウザ側から直接DBにCRUD操作できそう!とりあえずここから初めてみよう。
Firebase コンソールの [Realtime Database] セクションに移動
こんな画面。「データベースを作成」をクリック
ロケーションを設定、日本はないようだったのでアメリカのままで次へ
Firebase セキュリティ ルールの開始モードを選択
初期はロックモードになっている。読み書き禁止。
テストモードにすると1ヶ月後まで読み書きを許す内容。 まずはテストモードで初めてみる。
ルールについて
※参考:Understand Firebase Realtime Database Rules
※参考:基本的なセキュリティ ルール | Firebase
DBが作成された! 中身はまだない。
DBの設定と起動
DBの初期設定
次はDBの初期設定。
Realtime Database JavaScript SDK を初期化する
※参考:Installation & Setup in JavaScript | Firebase Realtime Database
このような設定をJSコードの頭の方に貼るようだ。
// Set the configuration for your app // TODO: Replace with your project's config object var config = { apiKey: "<apiKey>", authDomain: "<projectId>.firebaseapp.com", databaseURL: "https://<databaseName>.firebaseio.com", storageBucket: "<bucket>.appspot.com" }; firebase.initializeApp(config);
- 変数
config
の値は連想配列 - 連想配列の中で
apiKey
、authDomain
、databaseURL
、storageBucket
を設定(< >
は固有の値) firebase.initializeApp()
の引数にconfig
を入れて初期設定
自分の場合はこうなる。
// Config const config = { apiKey: "AIzaSyBju9iq3ug6gJMqyVsoGX_YByHt6L3Dh0c", authDomain: "kumokotsu-test.firebaseapp.com", databaseURL: "https://kumokotsu-test-default-rtdb.firebaseio.com", storageBucket: "kumokotsu-test.appspot.com" }; firebase.initializeApp(config);
APIキーはJSコードやGitHubで公開しても大丈夫なのか不安になる。
しかし調べると「大丈夫だよ」という情報ばかりだった。大船に乗ったつもりでこのままいく!
※参考:FirebaseのAPIキーは公開しても大丈夫だよ(2020年夏) - shiodaifuku.io
DBを取得
そのあと、クラウドからDBを取得する
const db = firebase.database();
- 変数
db
でfirebase.database()
を実行
これでRealtime Databaseが実行される。
HTMLを作成
前回のindex.htmlをコピーし「db-test.html」というファイルを作成。
このように書き換える
<div id="message"> <h2>りあるたいむ・でぇたべぇす</h2> <h1>CRUD操作テスト</h1> <p>ビートルズのメンバーをCRUDするの巻</p> <button type="button" class="crudBtn">実行</button> </div>
buttonタグ(.crudBtn
)を押したときにCRUDを実行するようにしたい
ローカル起動
毎回クラウド上にデプロイするのは大変なのでローカル起動する。こちらのコマンド
$ firebase serve
ブラウザを下記のURLを開く
http://localhost:5000/db-test.html
おお、ページが表示された!
DB初期設定エラー
Dev-toolsのconsoleを見ると下記のエラーが。。
Uncaught FirebaseError: Firebase: Firebase App named '[DEFAULT]' already exists (app/duplicate-app).
これはページ読み込み時に実行される先ほどのDB初期設定がエラーになっているということだ。
調べるとfirebase.initializeApp()
が複数回呼ばれていることが原因のようだった。
※参考:Firebaseで「Firebase App named '[DEFAULT]' already exists」というエラーがでた - Qiita
このようにしたらエラーが消えた。
if (firebase.apps.length === 0) { firebase.initializeApp(config); };
if文でfirebase.apps
がなければfirebase.initializeApp()
を実行するようにしている。
しかしデベロッパーツールでif文にブレイクポイントを付けても止まらない。 つまり、そもそもこのif文が動いてない。
試しに初期設定をコメントアウトしてみたが、問題なかった!
/* const config = { apiKey: "AIzaSyBju9iq3ug6gJMqyVsoGX_YByHt6L3Dh0c", authDomain: "kumokotsu-test.firebaseapp.com", databaseURL: "https://kumokotsu-test-default-rtdb.firebaseio.com", storageBucket: "kumokotsu-test.appspot.com" }; if (firebase.apps.length === 0) { firebase.initializeApp(config); }; */
おそらく前回インストールしたFirebaseのファイル一式の中にこちらの設定に相当する内容がすでに含まれているため、今回は設定が不要になったと思われる。(今後、必要な場面も出てくるかと思うので、このコメントはメモとして残しておく)
CRUD操作の設定
ドキュメント、参考記事
いよいよCRUD操作をしていく。基本的にはこちらのドキュメントを見ながら進める。
※参考:Read and Write Data on the Web | Firebase Realtime Database
メソッドの詳細はリファレンスを調べる。
※参考:Reference | JavaScript SDK | Firebase
その他参考にした記事。ドキュメントはいろんなページをぐるぐると循環してしまうがこちらの記事はとてもよりわかりすい!
※参考:FirebaseでCRUD処理の作成方法を解説 | とものブログ
DBの構造(ネストは浅く)
DBの構造についてはこちら。
※参考:Structure Your Database | Firebase Realtime Database
ネストは浅くして平坦にした方がパフォーマンスが良くなるようだ。
つっても今回はいつもDB事始めでやっているビートルズメンバーのCRUDなので、複雑になりようがないw
このような構造を想定している。
"member" { "1" { "id" : "1", "name" : "ジョン・レノン", "part": "ギター" } }
データの追加(Create)
まずはCRUDのC、データの追加(Create)
※参考:Read and Write Data on the Web | Firebase Realtime Database
// Create const createDB = (thisId, thisName, thisPart) => { db.ref('member/' + thisId).set({ id: thisId, name: thisName, part : thisPart }); };
- 変数
createDB
の値は無名関数(引数は左からthisId
,thisName
,thisPart
) db
でref()
メソッドを実行(引数はDBのパスでmember/
とthisId
を足した文字列)- 続いて
set()
メソッドを実行(引数はデータで連想配列) - 連想配列
id
キーの値はthisId
、name
キーの値はthisName
、part
キーの値はthisPart
引数の値を拾ってDBにデータを追加する。処理はメソッドチェーンになっている。
ref()
メソッド
Returns a Reference to the Query's location.
クエリの場所への参照を返します。
※参考:Reference | JavaScript SDK | Firebase
クエリとはDBに対する命令文のこと
※参考:https://wa3.i-3-i.info/word11290.html
set()
メソッド
Writes data to this Database location.
このデータベースの場所にデータを書き込みます。
※参考:Reference | JavaScript SDK | Firebase
データの取得(Read)
次はCRUDのR、データの取得(Read)
※参考:Read and Write Data on the Web | Firebase Realtime Database
// Read const readDB = (thisId) => { db.ref('member/' + thisId).on('value', (snapshot) => { const data = snapshot.val(); console.log(data.id); console.log(data.name); console.log(data.part); }); };
- 変数
readDB
の値は無名関数(引数はthisId
) db
でref()
メソッドを実行(引数はDBのパスでmember/
とthisId
を足した文字列)- 続いて
on()
メソッドを実行(引数はvalue
と無名関数、無名関数の引数はsnapshot
) - 無名関数の処理:変数
data
でsnapshot.val()
を実行
コンソールにdata.id
、data.name
、data.part
引数のIDのデータをコンソールに表示する。
on()
メソッド
Listens for data changes at a particular location.
特定の場所でのデータ変更をリッスンします。
リッスンしますてw
※参考:Reference | JavaScript SDK | Firebase
snapshot.val()
メソッド
Extracts a JavaScript value from a DataSnapshot.
DataSnapshotからJavaScript値を抽出します。
※参考:DataSnapshot | JavaScript SDK | Firebase
snapshotとは「その瞬間」の状態を丸ごと保存したもののこと。
※参考:https://wa3.i-3-i.info/word14388.html
この処理で得たデータをコンソールに表示している。
データの更新(Update)
次はCRUDのU、データの更新(Update)
※参考:Read and Write Data on the Web | Firebase Realtime Database
全体の更新は先ほどのデータ追加で同じIDを指定すると上書きになるようだったが、名前だけ、パートだけなど部分的に更新したい。
まず名前の更新
// Update (Name) const updateName = (thisId, thisName) => { db.ref('member/' + thisId).update({ name: thisName, }); };
- 変数
updateName
の値は無名関数(引数はthisId
、thisName
) db
でref()
メソッドを実行(引数はDBのパスでmember/
とthisId
を足した文字列)- 続いて
update()
メソッドを実行(引数は連想配列) - 連想配列の
name
キーの値はthisName
引数でIDと名前を入れるとそのIDのデータの名前を更新できる。
次にパートの更新
// Update (Part) const updatePart = (thisId, thisPart) => { db.ref('member/' + thisId).update({ part: thisPart, }); };
- 変数
updatePart
の値は無名関数(引数はthisId
、thisPart
) db
でref()
メソッドを実行(引数はDBのパスでmember/
とthisId
を足した文字列)- 続いて
update()
メソッドを実行(引数は連想配列) - 連想配列の
part
キーの値はthisPart
先ほどの名前更新と同じ構成でキーをpart
にした形。
update()
メソッド
Writes multiple values to the Database at once.
一度に複数の値をデータベースに書き込みます。
※参考:Reference | JavaScript SDK | Firebase
データの削除(Delete)
最後、CRUDのD、データの削除(Delete)
※参考:Read and Write Data on the Web | Firebase Realtime Database
// Delete const deleteDB = (thisId) => { db.ref('member/' + thisId).remove(); };
- 変数
deleteDB
の値は無名関数(引数はthisId
) db
でref()
メソッドを実行(引数はDBのパスでmember/
とthisId
を足した文字列)- 続いて
remove()
メソッドを実行
削除したいIDを指定してremove()
を実行するだけ。シンプル。
remove()
メソッド
Removes the data at this Database location.
このデータベースの場所にあるデータを削除します。
※参考:Reference | JavaScript SDK | Firebase
CRUD操作を実行
CRUD実行イベント
画面上にある「実行」ボタンを押すとCRUD操作を実行したい。
// CRUD Event const crudBtn = document.querySelector('.crudBtn'); crudBtn.addEventListener('click', () => { // 処理 }, false);
- 変数
crudBtn
でDOM. crudBtn
を取得 crudBtn
をクリックしたら処理を実行
クリックイベントの中に先ほど作った関数を書く。
ブラウザ動作確認
まずcreateDB()
でビートルズのリーダー、ジョンを追加する
// CRUD Event const crudBtn = document.querySelector('.crudBtn'); crudBtn.addEventListener('click', () => { createDB(1, 'ジョン・レノン', 'ギター'); }, false);
実行ボタンを押すとDBの1
にジョン・レノンが追加された!
以下、上記のイベント部分は省略し、中の処理のみ記載する(実際はイベントの中に書いている)
readDB()
でデータを取得する。
readDB(1);
コンソールにジョンのデータが表示された!
どんどんいこう、次はポールを追加!
createDB(2, 'ポール・マッカートニー', 'ギター');
2
にポールが追加された!
次はジョージを追加する。
createDB(3, 'ジョージ・ハリスン', 'ギター');
3
でジョージが追加された!
クオリーメン生え抜きメンバーが揃った。
ベースのスチュを追加
createDB(4, 'スチュアート・サトクリフ', 'ベース');
4
にスチュが追加された!
ドラムのピートを追加
createDB(5, 'ピート・ベスト', 'ドラム');
5
にピートが追加。デビュー前のハンブルグ巡業メンバーが揃った!
しかしハンブルグでスチュ脱退、芸術家の道へ。deleteDB()
で削除する。
deleteDB(4);
4
のピートが削除された。。
ジョンの指名でポールがベースに転向〜updatePart()
で更新。
updatePart(2, 'ベース');
2
のポールのpart
がベースになった!
苦楽を共にしたピートがデビュー直前に解雇される。そりゃないよセニュリータ。。
deleteDB(5);
5
のピートが削除された!
最後にドラムのリンゴを追加。これでファブ・フォーが揃う!
createDB(6, 'リンゴ・スター', 'ドラム');
6
にリンゴが追加された!
最後に全員分のデータを読み込んでみる。
readDB(1); readDB(2); readDB(3); readDB(6);
コンソールに4人分表示される。
最終形
最終的にこうなった(ボタンを押すと一度に全部を実行する)
// CRUD Event const crudBtn = document.querySelector('.crudBtn'); crudBtn.addEventListener('click', () => { createDB(1, 'ジョン・レノン', 'ギター'); // readDB(1); createDB(2, 'ポール・マッカートニー', 'ギター'); createDB(3, 'ジョージ・ハリスン', 'ギター'); createDB(4, 'スチュアート・サトクリフ', 'ベース'); createDB(5, 'ピート・ベスト', 'ドラム'); deleteDB(4); updatePart(2, 'ベース'); deleteDB(5); createDB(6, 'リンゴ・スター', 'ドラム'); readDB(1); readDB(2); readDB(3); readDB(6); }, false);
DB全体はこうなる。
ソース(GitHub)
Firebaseにデプロイ
デプロイ実行
これまでローカルで検証しいたが、完成したデータをFirebaseにデプロイする。*1
デプロイは下記のコマンド
$ firebase deploy
成功!
Deploy complete!
Firebase上でもページ(db-test.html)が表示された!
※参考:Welcome to Firebase Hosting
ブラウザ動作確認
ボタンをクリックするとコンソールにデータが表示された!
Dev-toolsの「Network」パネルを見ると
いつもは「Response」だが今回は「Message」になっている。
中にはジョン・レノンのデータなどもある。
おまけ:DBルール変更
DBのルールを「ロック」に変更してみる。
コンソールを見ると読み書きは実行されているが、パーミッション関係のエラーも起きている。
※参考:FirebaseのDBのパーミッションのエラー - 万年素人からHackerへの道
読み書きが実行されて、エラーが起こるだけだとあまり意味がないな…。元のテストモードに戻した。
最後に
ということでRealtime Databaseにブラウザから直接CRUD操作できました*2。
これまでブラウザ側にFetch API、サーバ側(Express)にCRUD操作、という構造にしていたのですが、Firebaseはブラウザ側にCRUD操作を書いて直接実行できたので楽に感じました。
また、RDBのようなテーブル設計をせずにいきなりデータを登録できたのも楽だなと感じました。逆にいうと無秩序なデータにもなりそうなんですが、ブラウザ側でフォーム項目や関数定義をちゃんと設定すればある程度は成立するんじゃないか、という気もします。
今後やってみたいこと:
FunctionsでAPIを作ってみたい。
※参考:Firebase Cloud Functions, Realtime DatabaseでCRUD REST WebAPIを作る - Qiita
※参考:Firebaseで動かすNode.jsアプリ入門🔥 - Qiita
Reactと連携してみたい。
(Reactime Database)
※参考:Firebase Realtime DatabaseをReactで使ってみる - Qiita
(Firestore)
※参考:新:React + FirestoreでCRUD(基礎編) - Qiita
それではまた!
※参考:Web開発環境についてのまとめ
qiita.com