DEV Community

Cover image for Firebase Cloud Firestore V9 常用功能筆記
Let's Write
Let's Write

Posted on • Originally published at letswrite.tw

Firebase Cloud Firestore V9 常用功能筆記

本篇大綱


本篇要解決的問題

之前寫過一篇 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);
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

有登入即可使用使用

這邊的「有登入」,指的是有登入同一個 Firebase 專案下的帳號,Authentication 的功能必須打開,並且登入,之前有寫過三篇,可以點開文章看怎麼使用登入功能:

帳密登入Google || FB 登入GitHub 登入

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

一律阻擋

不管誰來都阻擋,都無法讀寫資料庫:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

一律通過

不管是誰都可以讀寫資料庫,外星人來也可以:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if true;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

安全規則選定後,接著會選資料庫要放在哪個地區,這部份可以直接看文件,裡面有各個地區的資料庫主機是在哪個國家:

Regional locations


建立好 Cloud Firestore 後,Firebase 左側選單選擇專案總覽,右側點擊新增網頁應用程式:

新增應用程式

在建立完應用程式後,就會看到要怎麼安裝 Firebase SDK:

如何安裝 Firebase SDK

參照說明文件,我們只需要以下幾行就可以:

import { initializeApp } from "firebase/app"
import { getFirestore } from "firebase/firestore"
const firebaseApp = initializeApp({
  apiKey: 'XXXXXXXXXXX',
  authDomain: 'XXXXXXXXXXX',
  projectId: 'XXXXXXXXXXX'
});

const db = getFirestore();
Enter fullscreen mode Exit fullscreen mode

要記得,我們的檔案裡也要安裝 Firebase 的 package:

npm install firebase
Enter fullscreen mode Exit fullscreen mode

寫入資料

Firebase Cloud Firestore 的資料架構有三層,Collections > Documents > Data。

說明如下圖:

Firebase Cloud Firestore 資料架構

set 建立、覆蓋資料

第一種寫入資料的方式是 setDoc,可以指定 document 的名稱:

import { getFirestore, doc, setDoc } from "firebase/firestore"
const db = getFirestore();
await setDoc(doc(db, "collection 的名稱", "document 的名稱"), 資料, { merge: true });
Enter fullscreen mode Exit fullscreen mode

merge 是指要不要只覆蓋有更動過的資料的部份,true 可以避免原有的資料整個被覆蓋或被刪除掉,作用跟 update 相同。

範例:

try {
  await setDoc(doc(db, "users", "demo1"), {
    web: "Let's Write",
    author: "August",
    like: true
  });
} catch (err) {
  console.error("Error: ", err);
}
Enter fullscreen mode Exit fullscreen mode

第二種寫入資料的方式是 addDoc,適用於如果不想要指定 document 的名稱,想每次都直接配一個亂數時使用:

import { getFirestore, collection, addDoc } from "firebase/firestore"
const db = getFirestore();
let docRef = await addDoc(collection(db, "collection 的名稱"), 資料);
console.log(docRef.id); // => 亂數值
Enter fullscreen mode Exit fullscreen mode

範例:

try {
  let docRef = await addDoc(collection(db, "users"), {
    web: "Let's Write",
    author: "August"
  });
  console.log(docRef.id)
} catch (err) {
  console.error("Error: ", err);
}
Enter fullscreen mode Exit fullscreen mode

這樣不管送了幾次重覆的資料,由於 document 的名稱是亂數,就不會被誤蓋掉,資料庫上會看到像這樣:

隨機建立亂數 document id

update 更新資料

update 就是只會更新資料有變動的部份,不會原有的資料整個蓋掉,作用跟 setDocmerge 設為 true 一樣。

import { getFirestore, updateDoc } from "firebase/firestore"
const db = getFirestore();
await updateDoc(doc(db, "collection 的名稱", "document 的名稱"), 要更新的資料);
Enter fullscreen mode Exit fullscreen mode

範例:

try {
  await updateDoc(doc(db, "users", "demo1"), {
    web: "Let's Write",
    author: "Augusts"
  });
} catch (err) {
  console.error("Error: ", err);
}
Enter fullscreen mode Exit fullscreen mode

取得資料

取得資料分成二種:只取一次、監聽即時資料更新。

取一次資料

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())
}
Enter fullscreen mode Exit fullscreen mode

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());
});
Enter fullscreen mode Exit fullscreen mode

監聽即時資料更新

取得單一 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());
});
Enter fullscreen mode Exit fullscreen mode

取得取有 document 的資料變動

監聽某個 collection 裡所有 document 裡資料的任何變動,當其中一個 document 裡的某個值一有變動,就會回傳 collection 裡所有 document 裡的值。

const unsubscribe = onSnapshot(collection(db, 'users'), (querySnapshot) => {
  querySnapshot.forEach((doc) => {
    console.log(doc.data())
  });
});
Enter fullscreen mode Exit fullscreen mode

停止資料監聽

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(); // 停止監聽
Enter fullscreen mode Exit fullscreen mode

停止 取得取有 document 的資料變動

const unsubscribe = onSnapshot(collection(db, 'users'), (querySnapshot) => {
  querySnapshot.forEach((doc) => {
    console.log(doc.data())
  });
});

unsubscribe(); // 停止監聽
Enter fullscreen mode Exit fullscreen mode

真的方便~ 直接執行 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());
});
Enter fullscreen mode Exit fullscreen mode

查詢用的運算符有很多……多到 August 不想研究了(懶),就附上文件說明啦~

Query operators


刪除資料

刪除 data

要刪除 document 裡的某個資料:

import { getFirestore, doc, updateDoc, deleteField } from "firebase/firestore";
const db = getFirestore();
await updateDoc(doc(db, 'collection 的名稱', 'document 的名稱'), {
  要刪除的欄位名稱: deleteField()
});
Enter fullscreen mode Exit fullscreen mode

範例:

await updateDoc(doc(db, 'users', 'MTjUUsKj4hqKNZ6HqTmp'), {
  author: deleteField()
});
Enter fullscreen mode Exit fullscreen mode

刪除 document

要刪除 collection 裡的某個 document

import { getFirestore, doc, deleteDoc } from "firebase/firestore";
const db = getFirestore();
await deleteDoc(doc(db, "collection 的名稱", "document 的名稱"));
Enter fullscreen mode Exit fullscreen mode

範例:

await deleteDoc(doc(db, "users", "MTjUUsKj4hqKNZ6HqTmp"));
Enter fullscreen mode Exit fullscreen mode

刪除 collection

文件中說明不提供這樣子的 API,因為很危險,哪個人發神經一執行,就整個 collection 會從地球上消失。

如果真的要刪 collection,就是執行上面那段的「刪除 document」,然後一個一個 document 去刪。

Top comments (0)