DEV Community

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

Posted on • Originally published at letswrite.tw

4 4

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 去刪。

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay