跳到正文 Week 8 Pre-reading Overview: Firestore · Jimmy Huang's Blog
Firestore Basics - Vue 3 AI总结内容 核心内容要点 介绍 Cloud Firestore 的基本概念:一种文档型(NoSQL)数据库,数据以「集合(collections)/ 文档(documents)」组织,适合实时应用场景。 Firebase 在上一集完成 Firebase/Firestore 初始化之后(创建项目、注册 Web 应用、加载 SDK),本集开始在 Vue 3(Options API)中 实际读写 Firestore 。 YouTube 增(Create) :在某个集合中新增文档,演示如何把表单/页面数据写入 Firestore。 YouTube 查(Read) :从集合或文档读取数据,并在页面渲染展示结果。 YouTube 改(Update) :更新已有文档的一个或多个字段。 YouTube 删(Delete) :删除指定文档,页面同步反馈。 YouTube (延伸) 实时监听 :讲到/引出用监听器在数据变更时自动更新 UI 的思路(典型做法是 onSnapshot 订阅)。 Firebase KoderHQ 常见 API/关键点(视频所涉主题的典型用法) 官方页面与检索摘要显示:本集围绕 NoSQL 模型、集合/文档结构以及在 Firestore 中创建、读取、更新、删除数据的具体操作展开。YouTube
Vue.js 3 Firebase Firestore Setup Tutorial 主要介绍怎么在Firebase设置数据库,register app
Vue.js 3 Firestore Basics Tutorial
数据存储方式
addDoc addDoc(collectionReference, dataObject)
collection(firestoreInstance, 'collectionName')
已配置firestore实例
collection name
HTTP 请求会返回一个承诺,因此我们需要用 async 标记该方法才能在请求上使用 await
SetDoc setDoc(documentReference, dataObject)
doc(firestoreInstance, 'collectionName', 'documentID')
已配置firestore实例
collection name
document id
使用 setDoc 添加/合并新数据 setDoc(collectionReference, dataObject, { merge: true })
使用 updateDoc 更新文档中的现有数据 updateDoc(documentReference, dataObject)
document reference
dataObject
找到 :定位到 Firestore 数据库中的 countries 集合。
定位文档 :找到该集合中 ID 为 'GB' 的特定文档。
更新字段 : 更新 该文档中的 capital 字段,将其值更改为 'Londinium'
updateDoc 和 setDoc 的区别 updateDoc() 和 setDoc() 方法在功能上有些相似,但有一个关键区别:
当你确定文档已经存在,并且只想更新部分字段时, updateDoc() 是更安全、更明确的选择。
使用 getDoc 获取文档 getDoc(documentReference)
使用 exists方法来检查我们尝试获取的文档是否存在
Example about .data().field
使用 getDocs 获取多个文档 query(collectionReference, queryFilter())
collection reference
optional: query filter
使用 where 查询特定文档 where('key', operator, 'filter')
Example: 找出“用户”集合中所有 1990 年后出生的用户,并将他们打印到控制台
使用 orderBy 按特定字段对文档进行排序 orderBy('field', 'order')
使用 limit 限制获取文档的数量 Example: 将前面的示例限制为仅显示一个用户
使用 deleteDoc 删除文档 deleteDoc(documentReference)
Example: 让我们删除“countries”集合中的“US”文档
使用 deleteField 从文档中删除字段 Example: 从“countries”集合中的“GB”文档中删除“capital”字段
如何删除Collection
Realtime listeners 实时监听器允许我们的应用程序在数据发生变化或添加到数据库时自动更新
假设我们有一个应用,用于显示用户所在区域电影院上映的最新影片。如果用户正在浏览影片列表,而此时又有新影片上映,则页面会自动切换,显示列表中的新影片
为了演示默认行为,让我们创建一个按钮,将首都添加到我们的“国家”集合中的文档并将其输出到模板
如果我们在浏览器中运行示例并点击按钮,capital不会显示任何内容。但是,如果我们查看“GB”文档下的数据库,就会发现它确实存在。
We will have to refresh the page to see the capital.我们必须刷新页面才能看到首都。
如何在document上注册实时监听器 A document reference
用于处理数据的回调函数
用于处理监听错误的回调函数
这次当我们点击按钮时,模板中的文本会立即使用新的字段值进行更新
如何在collection上注册实时监听器
在查询结果上注册实时监听器 为了在查询结果上注册实时监听器,我们使用查询而不是文档/集合引用
Example: 为了演示,让我们将前面的示例更改为使用仅返回 1990 年后出生的用户的查询。
如何取消实时监听器的订阅 onSnapshot 方法返回一个取消订阅实时监听器的方法。因此,我们可以将其赋值给一个常量,然后在需要取消订阅的地方使用该常量调用该方法。
< template > < div ></ div > </ template > < script > // the relevant methods import { collection, addDoc } from "firebase/firestore" // the firestore instance import db from './firebase/init.js' export default { created() { this.createUser() }, methods: { async createUser() { // 'users' collection reference const colRef = collection(db, ' users ' ) // data to send const dataObj = { firstName: ' John ' , lastName: ' Doe ' , dob: ' 1990 ' } // create document and return reference to it const docRef = await addDoc(colRef, dataObj) // access auto-generated ID with '.id' console.log( ' Document was created with ID: ' , docRef.id) } } } </ script > < template > < div ></ div > </ template > < script > // the relevant methods import { doc, setDoc } from "firebase/firestore" import db from './firebase/init.js' export default { created() { this.createCountry() }, methods: { async createCountry() { await setDoc(doc(db, ' countries ' , ' US ' ), { name: ' United States ' }) } } } </ script > < template > < div ></ div > </ template > < script > import { doc, setDoc } from "firebase/firestore" import db from './firebase/init.js' export default { created() { this.addCountryCapital() }, methods: { async addCountryCapital() { await setDoc(doc(db, ' countries ' , ' GB ' ), { // new data capital: ' London ' // merge }, { merge: true }) } } } </ script > < template > < div ></ div > </ template > < script > // relevant methods import { doc, updateDoc } from "firebase/firestore" import db from './firebase/init.js' export default { created() { this.updateCountry() }, methods: { async updateCountry() { await updateDoc(doc(db, ' countries ' , ' GB ' ), { capital: ' Londinium ' }) } } } </ script > snapshot = getDoc(documentReference) snapshot.data() // full object snapshot.data().field // single field (key) snapshot = getDoc(documentReference) if (snapshot.exists()) { // document exists, use it } else { // document does not exist // .data() will be undefined } < template > < div ></ div > </ template > < script > // relevant methods import { doc, getDoc } from "firebase/firestore" import db from './firebase/init.js' export default { created() { this.getCountry() }, methods: { async getCountry() { const docSnap = await getDoc(doc(db, ' countries ' , ' GB ' )) if (docSnap.exists()) { console.log(docSnap.data()) } else { console.log( ' Document does not exist ' ) } } } } </ script > < template > < p > Country: {{ name }}< br > Capital: {{ capital }} </ p > </ template > < script > import { doc, getDoc } from "firebase/firestore" import db from './firebase/init.js' export default { data() { return { name: '' , capital: '' } }, created() { this.getCountry() }, methods: { async getCountry() { const docSnap = await getDoc(doc(db, ' countries ' , ' GB ' )) if (docSnap.exists()) { // assign document fields // to data properties this.name = docSnap.data().name this.capital = docSnap.data().capital } else { console.log( ' Document does not exist ' ) } } } } </ script > < template > < p v-for= " country in countries " :key="country.name"> Country: {{ country.name }}<br> Capital: {{ country.capital }} </p> </template> <script> import { query, collection, getDocs } from " firebase/firestore " import db from ' ./firebase/init.js ' export default { data() { return { countries: [] } }, created() { this.getCountry() }, methods: { async getCountry() { // query to get all docs in 'countries' collection const querySnap = await getDocs(query(collection(db, ' countries ' ))); // add each doc to 'countries' array querySnap.forEach((doc) => { this.countries.push(doc.data()) }) } } } </script> where( ' capital ' , ' == ' , ' Londinium ' ) < template > < p v-for= " user in users " :key="user.firstName"> {{ user.firstName }} {{ user.lastName }} </p> </template> <script> import { where, query, collection, getDocs } from " firebase/firestore " import db from ' ./firebase/init.js ' export default { data() { return { users: [] } }, created() { this.getUsers() }, methods: { async getUsers() { // filter to get users with 'dob' after 1990 const q = query(collection(db, ' users ' ), where( ' dob ' , ' > ' , ' 1990 ' )) const querySnap = await getDocs(q); querySnap.forEach((doc) => { this.users.push(doc.data()) }) } } } </script> < template > < p v-for= " user in users " :key="user.firstName"> {{ user.firstName }} {{ user.lastName }} </p> </template> <script> import { query, collection, getDocs, orderBy } from " firebase/firestore " import db from ' ./firebase/init.js ' export default { data() { return { users: [] } }, created() { this.getUsers() }, methods: { async getUsers() { // order users by name (alphabetical order) const q = query(collection(db, ' users ' ), orderBy( ' firstName ' )) const querySnap = await getDocs(q); querySnap.forEach((doc) => { this.users.push(doc.data()) }) } } } </script> < template > < p v-for= " user in users " :key="user.firstName"> {{ user.firstName }} {{ user.lastName }} </p> </template> <script> import { query, collection, getDocs, orderBy, limit } from " firebase/firestore " import db from ' ./firebase/init.js ' export default { data() { return { users: [] } }, created() { this.getUsers() }, methods: { async getUsers() { // limit the ordered users to 1 const q = query(collection(db, ' users ' ), orderBy( ' firstName ' ), limit(1)) const querySnap = await getDocs(q); querySnap.forEach((doc) => { this.users.push(doc.data()) }) } } } </script> < template > < div ></ div > </ template > < script > import { doc, deleteDoc } from 'firebase/firestore' import db from './firebase/init.js' export default { created() { this.dropCountry() }, methods: { async dropCountry() { await deleteDoc(doc(db, ' countries ' , ' US ' )) } } } </ script > updateDoc(documentReference, { field: deleteField() }) < template > < div ></ div > </ template > < script > import { doc, updateDoc, deleteField } from 'firebase/firestore' import db from './firebase/init.js' export default { created() { this.dropCapital() }, methods: { async dropCapital() { await updateDoc(doc(db, ' countries ' , ' GB ' ), { capital: deleteField() }) } } } </ script > < template > < p > Country: {{ name }}< br > Capital: {{ capital }} </ p > < button @click="addCountryCapital">Add Capital</button> </template> <script> import { doc, setDoc, getDoc } from ' firebase/firestore ' import db from ' ./firebase/init.js ' export default { data() { return { name: '' , capital: '' } }, created() { this.getCountry() }, methods: { async getCountry() { const docSnap = await getDoc(doc(db, ' countries ' , ' GB ' )) if (docSnap.exists()) { this.name = docSnap.data().name this.capital = docSnap.data().capital } }, async addCountryCapital() { // add capital to country await setDoc(doc(db, ' countries ' , ' GB ' ), { capital: ' London ' }, { merge: true }) } } } </script> onSnapshot( docReference, (snapshot) => { // handle data }, (error) => { // handle error } ) < template > < p > Country: {{ name }} (aka. {{ aka }})< br > Capital: {{ capital }} </ p > < button @click="addAlsoKnownAs">Add AKA</button> </template> <script> import { doc, setDoc, onSnapshot } from ' firebase/firestore ' import db from ' ./firebase/init.js ' export default { data() { return { aka: '' , name: '' , capital: '' } }, created() { this.getCountry() }, methods: { async getCountry() { // register realtime listener // for changes on 'GB' document onSnapshot(doc(db, ' countries ' , ' GB ' ), (snap) => { this.aka = snap.data().aka this.name = snap.data().name this.capital = snap.data().capital }) }, async addAlsoKnownAs() { // add 'aka' field to document await setDoc(doc(db, ' countries ' , ' GB ' ), { aka: ' United Kingdom ' }, { merge: true }) } } } </script> onSnapshot( collectionReference, (snapshot) => { }, (error) => { } ) < template > < p v-for= " user in users " :key="user.firstName"> {{ user.firstName }} {{ user.lastName }} </p> </template> <script> import { collection, onSnapshot } from ' firebase/firestore ' import db from ' ./firebase/init.js ' export default { data() { return { users: [] } }, created() { this.getUsers() }, methods: { async getUsers() { // use 'collection()' instead of 'doc()' onSnapshot(collection(db, ' users ' ), (snap) => { snap.forEach((doc) => { this.users.push(doc.data()) }) }) } } } </script> onSnapshot( query, (snapshot) => { }, (error) => { } ) < template > < p v-for= " user in users " :key="user.firstName"> {{ user.firstName }} {{ user.lastName }} </p> </template> <script> import { query, where, collection, onSnapshot } from ' firebase/firestore ' import db from ' ./firebase/init.js ' export default { data() { return { users: [] } }, created() { this.getUsers() }, methods: { async getUsers() { onSnapshot( // use 'query()' instead of a reference query(collection(db, ' users ' ), where( ' dob ' , ' > ' , ' 1990 ' )), (snap) => { snap.forEach((doc) => { this.users.push(doc.data()) }) }) } } } </script> const unsub = onSnapshot( reference/query, (snapshot) => { }, (error) => { } ) // later... unsub()