Firestore with VueJS

應用架構設計

前一篇 QRCode Scanner with VueJS 大概講述了 QRCode Scan 的主要設計狀況,這篇文章將會繼續探討 firestore 在後面運作方式與設計以及 firestore 的操作和 deploy。

具體的細節應用架構如下圖:

邏輯層

這邊採用 vue cli 去建立應用,會選用的原因除了整合度高,可以自選調用組件跟生態系,搭配 vuetify 這個組件把外觀跟設定統一達到開發效率高。

Build Web Apps with Vue JS 2 & Firebase | Udemy
Vue Vuex Firebase Messaging App (Slack Clone) | Udemy

由於每個專案和情境都不太相同,這邊不多作贅述和深入探討 vue cli 等配置方式。

Authentication

由於我們給廠商使用時必須有權限限制存取,使用了 firebase 當中的權限存取,就是提供了許多方式作身分驗證,詳細可以看 Firebase Authentication | Firebase

如果對於登入驗證實作細節代碼有興趣可以拜訪:
Authentication With Firebase and Vue router
Keeping firebase login stats with vuejs

loud Firestore

db.collection("users").doc(uid).get().then(doc => {
let user = doc.data();
this.user = {
name: user.name,
email: user.email,
};
});

Get data with Cloud Firestore | Firebase

collection 指的是節點,類似叢集,例如有 users 這個 collection 底下會有很多的資料,doc 是透過節點下的 key 去取得資料,接著透過 then,作各種取得資料,比較特別的是 get() 可以透過帶入 type 去決定取得方式 Interface: GetOptions | Firebase 預設如果伺服器沒辦法拜訪則會返回 cache,反之則會去取得,可以依照自己情境作調用。

這邊將資料取回後放入 vue.js 的 data 當中作 observe 方便後續存取更新。

當然可以一次取得 collection 下面的所有 documents,像是這樣:

db.collection("users").get().then(querySnapshot => {
querySnapshot.forEach(doc => {
console.log(doc.id, " => ", doc.data());
});
});

其他細節可以參考官方網站文件 Get data with Cloud Firestore | Firebase

Add or Set?

兩者之間的差異文件上有段簡單的描述:
Add data to Cloud Firestore | Firebase

When you use set() to create a document, you must specify an ID for the document to create.

意思是如果你用 set() 你必須去指定 id,反之如果你希望由 firebase 自動產生出 id 可以透過 add() 新建資料。

sometimes there isn’t a meaningful ID for the document, and it’s more convenient to let Cloud Firestore auto-generate an ID for you. You can do this by calling add():

關於更多的資料操作可以參考文件。

Get realtime updates

Firestore 最強大的特性是可以動態的取得資料並即時更新,如同 node.js + socket.io 透過 websocket,只是 client 與 server 端的 api 都已經幫你準備好了,他會在連結後建立監聽來確保資料同步。

Get realtime updates with Cloud Firestore | Firebase

db.collection("users").doc("Yish")
.onSnapshot(doc => {
console.log("Current data: ", doc.data());
});

支持監聽與各式操作監聽:

db.collection("users").onSnapshot(snapshot => {
snapshot.docChanges().forEach(change => {
if (change.type === "added") {
console.log("new user:", change.doc.data());
}
if (change.type === "modified") {
console.log("Modified user: ", change.doc.data());
}
if (change.type === "removed") {
console.log("Removed user: ", change.doc.data());
}
});
});

小技巧

在某些特定情境下,假如 users/yish/events 我必須監聽底下所有的內容更新狀態,可以透過 doc.ref 持續往底下監聽或查找:

db.collection("users").onSnapshot(snapshot => {
snapshot.docChanges().forEach(change => {
// 第一次呼叫
if (change.type === "added") {
console.log("new user:", change.doc.data());
}
// 更新修改
if (change.type === "modified") {
console.log("Modified user: ", change.doc.data());
}
// 確保檔案不會上下影響,是監聽下層
if (change.type !== "modified") {
change.doc.ref.collection("events")
.onSnapshot(querySnapshot => {
//do what you need
}
}
});
});

Firestore Rule

Firestore 節點規則可以限制存取節點,像是 users 可以讀取,但如果需要寫入則必須登入:

service cloud.firestore {
match /databases/{database}/documents {
match /users/{user} {
allow read: if true;
allow write: if request.auth.uid != null;
}
...
}

介面上也有提供對應的模擬工具,可以在正式寫之前模擬一下再把他寫在 firestore.rules

Firebase tools

GitHub — firebase/firebase-tools: The Firebase Command Line Tools
可以透過 google 提供的 工具進行佈署和 initial project。

小貼士
假定我們有一組活動有很多場次,譬如:

  • 1:00~2:00
  • 2:00~3:00
  • 4:00~5:00

時間到期時場次必須消失隱藏,但問題出現在剛剛我們的情況都會是在監聽資料的變化性,也就是觸發點是 firestore 接收到動作後去更新修改資料,但 client 如果是資料到期則無法更新,也就是說主動權是在 firestore on snapshot 上面,依照上面的情境我們可以使用:

// 設定一個 timer
data() {
return {
timer: null
};
// 每秒輪詢場次是否到期
created() {
this.timer = setInterval(() => {
this.events.forEach(event => {
event.sessions.forEach(session => {
this.isSessionExpired(session);
})
});
}, 1000)
}
// 執行完清除 timer
destroyed() {
clearInterval(this.timer);
},

取得資料建議從 created 取得在依序透過綁定方式放到 vue.js 當中,主要是 vue.js 生命週期的設計,可以參考 The Vue Instance — Vue.js

後記

這邊主要放在 firebase/firestore 的說明而不是放在 vue.js 當中是因為 vue.js 邏輯層會因為需求不同而會有截然不同的寫法,這次的專案我採用了 vuetify 這個 component framework 主要是需求方並沒有要求外觀並且強調易用性,所以採用這套以 material design 為基礎,並且與 vue.js 高度整合的框架,配合上 vue cli 3 的整合性和 firebase tools 提供的接口,快速開發和實作項目。

下一篇我們將討論 firestore cloud functions 與 algolia 如何整合達到 full-text search 的功能,Cheers 🎉