如何使用 Firebase Firestore 作為你的資料庫
一個設置 Firestore 作為資料庫的教程,這是一個非常方便的解決方案,可以解決你的儲存問題!
我有一個需求,需要為我的 成員俱樂部 創建一個儲存數據的地方,這是我教授編程的地方。
我希望我的用戶可以通過點擊一個按鈕來手動說“我完成了這個課程”。
基本上,我想為每個用戶存儲一個特定的對象。
設置 Firebase
我決定使用 Firebase 以及他們提供的 Firestore 資料庫 來實現這個需求。
它的免費版本是很慷慨的,每個月最多可以存儲 1GB 的數據,並且網絡傳輸量可以達到 10GB,這遠超出了我的預期。
在 Firebase 網站上打開 https://firebase.google.com/
Firebase 是一個由 Google 提供的產品,所以一旦你登錄到 Google,你也就登錄到 Firebase。
通過點擊“創建專案”來創建一個新的 Firebase 專案。
給它一個名字:
然後就完成了:
我點擊了 iOS 和 Android 旁邊的“Web”圖標,然後輸入了應用程序名稱:
Firebase 立即給了我需要的訪問密鑰,還附帶了一些示例代碼:
在這之後,Firebase 讓我添加一些數據庫的安全規則。
你可以選擇兩個默認選項:對每個人開放,或對每個人關閉。我選擇了對每個人開放,這是他們稱之為 測試模式。
就是這樣!我準備好了,可以創建一個集合了。
什麼是集合?在 Firestore 的術語中,我們可以創建許多不同的集合,並為每個集合分配文檔。
然後,文檔可以包含字段和其他集合。
這和其他 NoSQL 數據庫(比如 MongoDB)沒有太大區別。
我強烈建議觀看這個主題的 YouTube 播放列表,非常棒。
所以,我添加了一個我稱之為 users
的集合。
我希望使用一個特殊的字符串 id
來識別每個用戶。
前端代碼
現在我們進入 JavaScript 部分。
在頁腳中,我包含了 Firebase 提供的這兩個文件:
1 | <script src="https://www.gstatic.com/ |
然後,我添加了一個 DOMContentLoaded 事件監聽器,以確保在 DOM 準備好時運行代碼:
1 | <script> |
在這個區塊中,我添加了 Firebase 配置:
1 | const firebaseConfig = { |
我將這個對象傳遞給 firebase.initializeApp()
,然後調用 firebase.firestore()
來獲取對數據庫對象的引用:
1 | firebase.initializeApp(firebaseConfig) |
現在,我創建了一個腳本來從後端列表中填充用戶 ID:
1 | const list = [/*...my list...*/] |
我運行了一次該腳本,以填充數據庫。我基本上是以程序化的方式 為每個用戶創建了一個文檔。
這非常重要,因為一旦我創建了一個文檔,它意味著我可以限制權限只能更新這些文檔,不允許添加新文檔或刪除它們(這是我們稍後要做的事情)。
好的,現在我有一些複雜的邏輯來識別用戶 ID 和課程 ID,這與我們這裡的任務無關,所以我不會詳細介紹。
一旦我獲取了這些信息,我就可以獲取該對象的引用:
1 | const id = /* the user ID */ |
太好了!現在,我可以從 Firebase 獲取文檔引用:
1 | docRef.get().then(function(doc) { |
我的邏輯實際上要複雜得多,因為有其他的可移動部分,但你明白了!
通過調用 doc.data()
,我初始化了文檔數據,當按鈕被點擊時(我假設它是“我完成了課程”的按鈕),我將 true
布爾值關聯到俱樂部標識符。
稍後,在每次加載課程列表頁面時,我可以初始化頁面並為已完成的課程分配一個類,就像這樣:
1 | for (const [key, value] of Object.entries(data[course])) { |
權限問題
我在測試模式下啟動了 Firebase,還記得嗎?這使得數據庫對每個人都是開放的 - 對具有公開且在前端代碼中發布的訪問密鑰的所有人都是開放的。
所以我必須做一件事:決定允許的權限級別。
這給我帶來了一個非常重要的問題。
使用 Firebase 控制台,在 Rules 下,我們可以設置權限。最初,這是默認規則:
1 | rules_version = '2'; |
我將規則更改為 read, update
,這樣只允許更新文檔,不允許創建新文檔:
1 | rules_version = '2'; |
但我無法阻止人們使用 Firebase API 在瀏覽器中進行操作,從而列出集合中的所有其他文檔 - 從而獲取到其他人的文件。
雖然這並沒有涉及到任何敏感數據,但無法發布這段代碼。
通過自定義 API,從前端將代碼移至後端
權限問題是一個擋路石。
我考慮刪除所有我已經有的代碼,但最終我想出了一個辦法,完全隱藏了瀏覽器中的所有 API 訪問,並使用 Node.js 服務器運行 Firebase API。
這也是隱藏服務所需的私密/密鑰的常見方法:將其隱藏在你控制的服務器後面。
我創建了一個自己的服務器上的一組端點,例如:
- POST 到
/course
來設置一門課程已完成 - POST 到
/data
來獲取與用戶關聯的數據
並使用 Fetch API 訪問它們:
1 | const options = { |
當然,所有與按鈕點擊等相關的邏輯仍然存在於客戶端代碼中,我只是將 Firebase 邏輯移到了其他地方。
在 Node.js 服務器端,我使用 npm install firebase
安裝了官方的 firebase
包並引入它:
1 | const firebase = require('firebase') |
我設置了一個 Express 服務器,使用 CORS,並初始化了 Firebase:
1 | const firebaseConfig = { |
然後,代碼與我在前端使用的代碼完全相同,只是現在在 HTTP 端點調用時觸發。這是從我們的集合返回特定文檔的代碼:
1 | const getData = async (id) => { |
這是將一門課程設置為已完成的 API 代碼:
1 | const setCourseAsCompleted = async (id, course) => { |
基本上就是這樣了。還需要一些更多的代碼來處理其他邏輯,但 Firebase 的精髓就是我所發布的這個。現在我也可以為我的服務器端服務添加用戶,並將所有其他對於 Firebase API 的訪問限制在僅允許我的服務器進行,從而加強它的安全性。
tags: [“firebase”, “firestore”, “database”, “tutorial”]