這一章介紹 Document 的概念,包含:
- 資料型別的包裝 AngularFirestoreDocument
- 如何取得單純的資料
.valueChanges()
- 如何取出資料以外的附帶資訊
.snapshotChanges()
AngularFirestore 裡的文件(Documents)
Cloud Firestore 是一種 NoSQL、文件導向的資料庫。你的資料將以文件 (doctument) 的形式儲存,並以集合 (collection) 的方式管理。每一個文件都是 key-value 的格式。Cloud Firestore 改良自 Realtime Database,更適合小型文件與大量集合。
AngularFirestoreDocument
AngularFirestoreDocument
service 是 Firestore SDK 的 DocumentReference
型態的包裝。它是一個泛型的服務,以強型別的方法操作資料流,並以依賴注入的方式使用。
這裡示範取得 item collection 裡面的一個 document。每個 Item 文件裡只有一個 name 的欄位。
"items" : [ "1" : {"name":"item1"} ]
import { Component } from '@angular/core';
import { AngularFirestore, AngularFirestoreDocument } from '@angular/fire/firestore';
import { Observable } from 'rxjs';
export interface Item { name: string; }
@Component({
selector: 'app-root',
template: `
<div>
{{ (item | async)?.name }}
</div>
`
})
export class AppComponent {
private itemDoc: AngularFirestoreDocument<Item>;
item: Observable<Item>;
constructor(private afs: AngularFirestore) {
this.itemDoc = afs.doc<Item>('items/1');
this.item = this.itemDoc.valueChanges();
}
update(item: Item) {
this.itemDoc.update(item);
}
}
使用 AngularFirestore.doc('集合id/文件id').valueChanges() 取回一個文件資料。
泛型
前面提到 AngularFirestoreDocument 可以宣告泛型,所以我們要做一個 Item 接口去接資料。
export interface Item { name: string; }
通常會寫在 shared/Item.ts
。
然後 afs.doc<Item>('items/1');
可以用泛型方法。
如果有泛型就可以取得回傳的資料結構:
getItem() {
return this.firestore.doc<Item>('item/1').valueChanges(); //return Observable<Item>
}
//component
getItem() {
//return Observable<Item>
console.log(this.todoService.getItem());
//subscribe Observer
this.todoService.getItem().subscribe(data => {console.log(data.name)}); //item1
}
如果沒有泛型:
//service
getItem() {
return this.firestore.doc('item/1').valueChanges(); //return Observable<unknown>
}
這邊做 data.name 會取不到屬性。
//component
getItem() {
//return Observable<Unkwon>
console.log(this.todoService.getItem());
//subscribe Observer
this.todoService.getItem().subscribe(data => {console.log(data)}); //{name: "item1"}
}
.valueChanges()
.valueChanges()
是 AngularFirestoreDocument
提供的方法,會回傳 Observable 的文件資料 (data) ,也就是前面範例看到的純資料本身 Observable<Item>
。
其他資料流的方法都是返回 DocumentChangeAction[]
。
DocumentChangeAction
包含兩個屬性:type、playload。
interface DocumentChangeAction {
type: DocumentChangeType;
payload: DocumentChange;
}
DocumentChangeAction
簡略的結構是這樣:
{
payload:{
doc:{
doc:{
data()
}
}
}
純資料本身就是最後的 data()。
通常單純需要文件資料時使用 .valueChanges()
,但當需要資料以外的附帶資訊時就不會使用,例如需要處理資料 id。如果要取得更多附帶的資訊就要用 snapshotChanges()
,它會返回一個 Observable 的 DocumentChangeAction
操作資料
除了剛剛介紹的讀取,還有:
- set(data: T) - Destructively updates a document's data.
- update(data: T) - Non-destructively updates a document's data.
- delete() - Deletes an entire document. Does not delete any nested collections.
巢狀結構
前面的範例結構是 集合-文件
"items" : [
"1" : {
"name":"item1"
}
]
但文件裡當然可以存放陣列結構
"items" : [
"1" : {
"name":"item1",
"insideItem":[]
}
]
這邊提供一個範例:
constructor(private afs: AngularFirestore) {
this.userDoc = afs.doc<Item>('user/david');
this.tasks = this.userDoc.collection<Task>('tasks').valueChanges();
}