Cloud FireStoreとVue.jsでデーターベース通信を行う
【所要時間】
4時間くらい(2019年5月11日)
【概要】
- Cloud FireStoreを使う。(まだ完全に理解したところ。)
- 前回Vue.js, Handsontableで作成したテーブルのデータをCloud FireStoreに保存する。
- 完成サイト
- 完成レポジトリ
【要約・学んだこと】
Cloud FireStoreとは?
Google の柔軟でスケーラブルな NoSQL クラウド データベースを使用して、クライアント側開発とサーバー側開発のデータを保存、同期します。
Cloud Firestore は、Firebase と Google Cloud Platform からのモバイル、ウェブ、サーバー開発に対応した、柔軟でスケーラブルなデータベースです。Firebase Realtime Database と同様に、リアルタイム リスナーを介してクライアント アプリ間でデータを同期し、モバイルとウェブのオフライン サポートを提供します。これにより、ネットワークの遅延やインターネット接続に関係なく機能するレスポンシブ アプリを構築できます。Cloud Firestore は、その他の Firebase および Google Cloud Platform プロダクト(Cloud Functions など)とのシームレスな統合も実現します。
公式ドキュメントより引用。
なるほど、流石によくわからない。
が、
- モバイルからもウェブからもいける。
- リアルタイムリスナー、オフラインサポートがある。
という2点で問題なく利用できそうで、便利そう。さらにfirebase hosting(作ったアプリをWebサイトにデプロイするやつ)がgit hub pagesより簡単に使えたこともあったので採用。
Cloud FireStoreがどんな感じか
他のデータベースがどうなのかわからないが、通信が早い上に、コンソール上(ウェブサイト上)のデータもリロードなしで即時に反映される。
Gifだから速度は分かりにくいが, 0.5秒程度で内容が反映されているのがわかる。
とりあえずこちらのサイトで通信が早いのを確認してみるといいでしょう。
データベース構造
コレクション/ドキュメント/フィールド
という階層になっている。ドキュメントの下層にサブコレクションを追加することも可能。
その場合は
コレクション/ドキュメント/コレクション/ドキュメント/フィールド
という階層になる。コレクションは何階層にもできそう。
詳しくはこちら
Vue.Cloud FireStoreの使い方をざっくり
簡単3ステップ!(その前にアプリをデプロイする必要がある。firebase hostingのページを参照。簡単。)
- firebase console上(ウェブサイト上)でプロジェクトを作成
- アプリ側(Vue.js)での設定ファイルを作成
- アプリ側で通信するためのコードを作成。
1. firebase console上(ウェブサイト上)でプロジェクトを作成
ドキュメントにしたがって作成するのみ。
- Firebase コンソールからプロジェクトを作成
- 開発→Databaseをクリック
- データベースの作成をクリック
- テストモードで開始
これでOK。この場でデータベースの作成もできる。
- コレクションを追加
ドキュメントIDを設定
これでデータベースができました。今どのようなデータベースになっているかも視覚的にわかりやすい。
2. アプリ側(Vue.js)での設定ファイルを作成
- firebaseモジュールのインストール
yarn add firebase
- 設定ファイルの作成
ここはむずかった。かりにくかったが、やっていることはシンプル。ただしいアプローチなのかわからないが、とりあえず動く。
コンソールの歯車マーク→プロジェクトの設定をクリック
Firebase SDK snippetの構成をコピー
firebase設定用のファイルを作成し、const configに先ほどの内容をペースト。
// /firebase.jsimport firebase from "firebase/app";
import "firebase/firestore";const config = {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: ""
}
firebase.initializeApp(config);firebase.firestore();export default firebase;
configの内容を公開してしまうとよくないので、環境変数を使い、.gitignoreに.envを追加するのがいいと思われる。
const config = {
apiKey: process.env.VUE_APP_API_KEY,
authDomain: process.env.VUE_APP_AUTH_DOMAIN,
databaseURL: process.env.VUE_APP_DATABASE_URL,
projectId: process.env.VUE_APP_PROJECT_ID,
storageBucket: process.env.VUE_APP_STORAGE_BUCKET,
messagingSenderId: process.env.VUE_APP_MESSAGING_SENDER_ID,
appId: process.env.VUE_APP_APP_ID
};
firebase.js自体をgitignoreにいれた方が楽だが、存在自体を忘れてしまう、存在自体を知らないといったことが起こりうるので、プロジェクトに必要なファイルは.gitignoreしない方がいいと思う派。
これで完了。
参考サイト
上記サイトと現在のバージョンでは記述方法が違うが、問題がある箇所をブラウザのコンソールにどこをどう修正すればいいか警告を出してくれる。(スクショとりわすれた)
変更点は
// import firebase from "firebase";import firebase from "firebase/app";
import "firebase/firestore";
使用するfirebaseツールのみインポートせよ。
// const settings = { timestampsInSnapshots: true };// firebase.firestore().settings(settings);
timeStampの設定は不要。
の2箇所。
3. アプリ側で通信するためのコードを作成。
- フィールド(データ)を取得
コレクション、ドキュメントを指定して、そのあとにリクエスト内容を記述する。という分かりやすいコード。
まずはデータ通信を行うドキュメントの指定。今回はtest1コレクションのtableドキュメントとのデータ通信を行いたい。
import firebase from "@/firebase/firebase.js";const tableDatabase = () => {
firebase.firestore().collection("test1").doc("table")
}
そのまんま。これでtableDatabaseがtest1/tableを表す変数になった。
次にテーブルフィールドを取得。
const tableData = tableDatabase.get();
テーブルフィールドの中身を参照。
console.log(tableData.data())
これだけ。
ここに少しハマった。まずtableDataが参照しているのが
こんな感じになっている。まさかいちいち整形する必要があるのかと思ったが、data()で問題なくfirestoreの中身が取得できる。
もう一つ失敗した点は、get().data()を同時に行おうとするとうまくいかない。
const tableData = await this.getData().data();
console.log(tableData)
この2点に注意。
データの取得はこちらを参照。
- その他のfirestoreのリクエスト
- データの上書き
set(): ドキュメントを指定し、フィールドを上書きする。
firebase.firestore().collection("test1").doc("table").set({
sample: [
{id:1, name: "test1"},
{id:2, name: "test2"}
]
});
オブジェクトで送信するデータを送る。こちら参照。
- add(): ドキュメントを指定せずにフィールドを上書きする。
firebase.firestore().collection("test1").add({
sample: [
{id:1, name: "test1"},
{id:2, name: "test2"}
]
});
この場合新規のドキュメントが作成され、ドキュメント名はランダムになる。こちら参照。
2. update(): 上書きせずにフィールドを更新する。
存在しない項目はフィールドに新規作成され、存在している項目は上書きされる。こちら参照。
3. delete(): コレクション、ドキュメント、フィールドを削除する。
そのまんま。こちら参照。
4. onSnapshot(): リアルタイムアップデート。ドキュメントをリッスンできる。
これやばい。つまり誰かがデータを更新していると、それをみている誰かのデータが更新される。
listenData: function() {
return new Promise(resolve => {
resolve(
this.tableDatabase.onSnapshot(data => {
this.members = data.data().members;
})
);
});
},
5. 他にもトランザクションや一括書き込みなどがあるが、今回は使用していない。
実際にデータを取得しているコード
Vue/cliで記述すると下記のようになる。sampleData.jsにオブジェクトを格納している。
// TableIndex.vue<template>
<div>
<Handsontable
:members="members"
:department="department"
:table-database="tableDatabase"
@getTableContents="getTableContents"
@updateMembers="updateMembers"
/>
</div>
</template><script>
import api from "axios";
import Handsontable from "./Handsontable";
import firebase from "../../firebase.js";
import sampleData from "./sampleData.js";export default {
name: "TableIndex",
components: {
Handsontable
},
data: function() {
return {
members: [],
department: []
};
},
computed: {
tableDatabase: () =>
firebase
.firestore()
.collection("test1")
.doc("table")
},
methods: {
listenData: function() {
return new Promise(resolve => {
resolve(
this.tableDatabase.onSnapshot(data => {
this.members = data.data().members;
})
);
});
},
setSampleData: function() {
return new Promise(resolve => {
resolve(this.tableDatabase.set(sampleData));
});
},
getData: function() {
return new Promise(resolve => {
resolve(this.tableDatabase.get());
});
},
getTableContents: async function() {
try {
await this.listenData();
// await this.setSampleData();
const tableData = await this.getData();
const membersData = tableData.data().members;
const departmentData = tableData.data().department;membersData.map(key => (key.initial = true));this.members = membersData;
this.department = departmentData;
} catch (err) {
alert(err);
}
},
updateMembers: function(payload) {
this.members = payload;
}
}
};
</script>
sampleData.jsは下記のよう感じ。
const sampleData = {
department: ["Marketing", "Engineering", "Accounting"],
members: [
{
id: 1,
name: "Paul",
mail: "paul@mail.com",
department: "Marketing",
position: "Manager"
},
{
id: 2,
name: "Tom",
mail: "tom@mail.com",
department: "Engineering",
position: "Manager"
},
...]
};export default sampleData;
まとめ
- Cloud Firestoreの設定は楽。(細かい設定はやってない)
- 設定ファイルの作り方が謎だったが、そこさえできれば何も難しくない。(知っていれば簡単)
- get, post, updateは簡単に記述できる。
- エラーメッセージが丁寧。
- onSnapshot()のリッスン機能がなんかすごい。
以上。
【わからなかったこと】
- 設定ファイルの作り方が公式ドキュメントからは理解できなかった。
【感想】
- json-serverがデプロイすると簡単には使えなくなるので使ってみた。
- データベースが個人でサクッと立てられるのはフロントエンドエンジニアとしては本当に助かる。
- node.js(reactとかvueを動かすやつね。)を優先的にサポートしているような感じなのもありがたい。
- これからもfirebase使っていこうと思った。