本篇大綱
本篇要解決的問題
之前寫過一篇 Version 8 版的,結果人生就是第 8 版都還沒用熟,就有了第 9 版,就像 Tailwind CSS 一樣啊,V2 版才記得剛補上段落,就這樣又出了 V3 是怎麼回事,這怎麼弄麻。
因為 Version 8 那篇很長,找不到地方塞第 9 版的說明進去,就專門寫成這篇筆記文囉。
主要參考文件是 Firebase 上的官方文件:Cloud Firestore
安裝 Firebase SDK
先進入到 Firebase 的後台建立一個專案。
接著 Firebase 後台左側選單,選擇「Firestore Database」,右側點擊「建立資料庫」:
下一步,會出現安全規則的選項,有正式模式、測試模式,這之後可以修改,參照 說明文件,總共有四種安全模式可以用,說明如下。
測試模式
一段時間之內,路人也都可以讀寫資料庫。
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if
request.time < timestamp.date(2022, 2, 16);
}
}
}
有登入即可使用使用
這邊的「有登入」,指的是有登入同一個 Firebase 專案下的帳號,Authentication 的功能必須打開,並且登入,之前有寫過三篇,可以點開文章看怎麼使用登入功能:
帳密登入、Google || FB 登入、GitHub 登入
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
一律阻擋
不管誰來都阻擋,都無法讀寫資料庫:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}
一律通過
不管是誰都可以讀寫資料庫,外星人來也可以:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
安全規則選定後,接著會選資料庫要放在哪個地區,這部份可以直接看文件,裡面有各個地區的資料庫主機是在哪個國家:
建立好 Cloud Firestore 後,Firebase 左側選單選擇專案總覽,右側點擊新增網頁應用程式:
在建立完應用程式後,就會看到要怎麼安裝 Firebase SDK:
參照說明文件,我們只需要以下幾行就可以:
import { initializeApp } from "firebase/app"
import { getFirestore } from "firebase/firestore"
const firebaseApp = initializeApp({
apiKey: 'XXXXXXXXXXX',
authDomain: 'XXXXXXXXXXX',
projectId: 'XXXXXXXXXXX'
});
const db = getFirestore();
要記得,我們的檔案裡也要安裝 Firebase 的 package:
npm install firebase
寫入資料
Firebase Cloud Firestore 的資料架構有三層,Collections > Documents > Data。
說明如下圖:
set 建立、覆蓋資料
第一種寫入資料的方式是 setDoc
,可以指定 document
的名稱:
import { getFirestore, doc, setDoc } from "firebase/firestore"
const db = getFirestore();
await setDoc(doc(db, "collection 的名稱", "document 的名稱"), 資料, { merge: true });
merge
是指要不要只覆蓋有更動過的資料的部份,true
可以避免原有的資料整個被覆蓋或被刪除掉,作用跟 update
相同。
範例:
try {
await setDoc(doc(db, "users", "demo1"), {
web: "Let's Write",
author: "August",
like: true
});
} catch (err) {
console.error("Error: ", err);
}
第二種寫入資料的方式是 addDoc
,適用於如果不想要指定 document
的名稱,想每次都直接配一個亂數時使用:
import { getFirestore, collection, addDoc } from "firebase/firestore"
const db = getFirestore();
let docRef = await addDoc(collection(db, "collection 的名稱"), 資料);
console.log(docRef.id); // => 亂數值
範例:
try {
let docRef = await addDoc(collection(db, "users"), {
web: "Let's Write",
author: "August"
});
console.log(docRef.id)
} catch (err) {
console.error("Error: ", err);
}
這樣不管送了幾次重覆的資料,由於 document
的名稱是亂數,就不會被誤蓋掉,資料庫上會看到像這樣:
update 更新資料
update
就是只會更新資料有變動的部份,不會原有的資料整個蓋掉,作用跟 setDoc
的 merge
設為 true
一樣。
import { getFirestore, updateDoc } from "firebase/firestore"
const db = getFirestore();
await updateDoc(doc(db, "collection 的名稱", "document 的名稱"), 要更新的資料);
範例:
try {
await updateDoc(doc(db, "users", "demo1"), {
web: "Let's Write",
author: "Augusts"
});
} catch (err) {
console.error("Error: ", err);
}
取得資料
取得資料分成二種:只取一次、監聽即時資料更新。
取一次資料
getDoc 取單一 document 的資料
如果是要取得某個 collection
裡,單一 document
的資料:
import { getFirestore, doc, getDoc } from "firebase/firestore";
const db = getFirestore();
const docSnap = await getDoc(doc(db, "collection 的名稱", "document 的名稱"));
if(docSnap.exists()) {
console.log(docSnap.data())
}
getDocs 取所有 document 的資料
如果是要取得某個 collection
裡,所有 document
的資料:
import { getFirestore, collection, getDocs } from "firebase/firestore";
const db = getFirestore();
const querySnapshot = await getDocs(collection(db, "collection 的名稱"));
querySnapshot.forEach(doc => {
console.log(doc.id, doc.data());
});
監聽即時資料更新
取得單一 document 資料變動
監聽某一個 document
裡的資料變動,當 document
裡的值一有變動,就會回傳 document
裡所有的值。
import { getFirestore, doc, onSnapshot } from "firebase/firestore";
const db = getFirestore();
const unsub = onSnapshot(doc(db, "collection 的名稱", "document 的名稱"), (doc) => {
console.log(doc.data());
});
取得取有 document 的資料變動
監聽某個 collection
裡所有 document
裡資料的任何變動,當其中一個 document
裡的某個值一有變動,就會回傳 collection
裡所有 document
裡的值。
const unsubscribe = onSnapshot(collection(db, 'users'), (querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(doc.data())
});
});
停止資料監聽
Firebase Cloud Firestore 是用讀寫次數在收費的(一個月有免費額度),如果每個使用者一進到頁面上,所有欄位都監聽變動,就很有可能會要收費,因此 Firestore 有提供停止監聽資料變動的方法。
其實從上面監聽資料變動的命名變數上,就可以猜到使用方式,這也是 August 看文件時驚訝的。
停止 取得單一 document 資料變動
import { getFirestore, doc, onSnapshot } from "firebase/firestore";
const db = getFirestore();
const unsub = onSnapshot(doc(db, "collection 的名稱", "document 的名稱"), (doc) => {
console.log(doc.data());
});
unsub(); // 停止監聽
停止 取得取有 document 的資料變動
const unsubscribe = onSnapshot(collection(db, 'users'), (querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(doc.data())
});
});
unsubscribe(); // 停止監聽
真的方便~ 直接執行 function 就可以了。
查詢資料
我們在取資料庫中的資料時,可以不用整個 collection
或整個 document
都取回來後,再自己去把要的資料濾出來,Firestore 有提供查詢的功能,可以只返還我們要查的資料。
const ref = collection(db, "users");
const q = query(ref, where("web", "==", "Let's Write"));
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
console.log(doc.id, doc.data());
});
查詢用的運算符有很多……多到 August 不想研究了(懶),就附上文件說明啦~
刪除資料
刪除 data
要刪除 document
裡的某個資料:
import { getFirestore, doc, updateDoc, deleteField } from "firebase/firestore";
const db = getFirestore();
await updateDoc(doc(db, 'collection 的名稱', 'document 的名稱'), {
要刪除的欄位名稱: deleteField()
});
範例:
await updateDoc(doc(db, 'users', 'MTjUUsKj4hqKNZ6HqTmp'), {
author: deleteField()
});
刪除 document
要刪除 collection
裡的某個 document
:
import { getFirestore, doc, deleteDoc } from "firebase/firestore";
const db = getFirestore();
await deleteDoc(doc(db, "collection 的名稱", "document 的名稱"));
範例:
await deleteDoc(doc(db, "users", "MTjUUsKj4hqKNZ6HqTmp"));
刪除 collection
文件中說明不提供這樣子的 API,因為很危險,哪個人發神經一執行,就整個 collection
會從地球上消失。
如果真的要刪 collection
,就是執行上面那段的「刪除 document」,然後一個一個 document
去刪。
Top comments (0)