AngularFirestore 教學 (1) : Document


Posted by JnTng on 2020-07-31

這一章介紹 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();
  }

參考資料


#angularfirestore crud #AngularFire Quickstart #Angular #Firebase #Firestore







Related Posts

邪魔歪道還是苦口良藥?Functional CSS 經驗分享

邪魔歪道還是苦口良藥?Functional CSS 經驗分享

DJI Tello 的基礎操作與套件

DJI Tello 的基礎操作與套件

以人為本 — 團隊中的核心元素

以人為本 — 團隊中的核心元素



Comments