Firestoreの基本リファレンス

まずはこれだけ覚えておけ的なやつ

## 基本
全部Promiseで返ってくる。

### Get = `get`
```JavaScript
db.collection("cities").doc("SF").get()
    .then( doc => doc.data() );
```

### Create, Update = `set`
```JavaScript
db.collection("cities").set({
    name: "San Francisco", state: "CA", country: "USA",
    capital: false, population: 860000,
    regions: ["west_coast", "norcal"] });
```

### Partial Update = `update`
```JavaSCript
db.collection("cities").doc("DC").update({
    capital: true
});
```

### Delete = `delete()`
```JavaScript
db.collection("cities").doc("DC").delete()
```

### Query
```JavaScript
db.collection("cities").where("capital", "==", true).get()
    .then( querySnapshot => {
        querySnapshot.forEach( doc => doc.data() );
    });
```
```JavaScript
db.collection("cities").where("population", ">", 100000).orderBy("population","desc").limit(3);
```

### Transaction
```JavaScript
const sfDocRef = db.collection("cities").doc("SF");

return db.runTransaction( transaction => {
    // This code may get re-run multiple times if there are conflicts.
    return transaction.get(sfDocRef)
      .then( sfDoc => {
          if (!sfDoc.exists) {
              throw "Document does not exist!";
          }
          const newPopulation = sfDoc.data().population + 1;
          transaction.update(sfDocRef, { population: newPopulation });
      });
});
```
async/awaitでまとめて書いたほうが読みやすそう。


## Streaming
https://firebase.google.com/docs/firestore/query-data/listen

`onSnapshot` を使う。

```JavaScript
db.collection("cities").doc("SF")
    .onSnapshot(doc => doc.data() );
```

onSnapshotに渡しているのは、リスナーという扱いになる。
コンテンツが変更されるたびに、リスナーにデータが流れる。

### Metadata
このとき、`doc` には `doc.metadata` のかたちでmetadataがついている。
metadataには、例えば `metadata.hasPendingWrites` プロパティなどがあり、ローカルでは変更されたがサーバ側では変更が終わってない、みたいな情報が付与されている。

また、リスナーで受け取るイベントの詳細レベルを制御することもできる。メタデータの変更があった場合のみListenする場合

```JavaScript
db.collection("cities").doc("SF")
    .onSnapshot({
        // Listen for document metadata changes
        includeMetadataChanges: true
    }, function(doc) {
        // ...
    });
```

### docChanges()

```JavaScript
db.collection("cities").where("state", "==", "CA")
    .onSnapshot(doc => {
        doc.docChanges().forEach( change => {
            if (change.type === "added") {
                console.log("New city: ", change.doc.data());
            }
            if (change.type === "modified") {
                console.log("Modified city: ", change.doc.data());
            }
            if (change.type === "removed") {
                console.log("Removed city: ", change.doc.data());
            }
    });
```
コレクションへのクエリ結果の変更状況をリスニングする場合。
都市が追加されたら、`added` typeのchangeが発生する。

### AngularFire
AngularFireでは、これらをObservableで取り扱えるように抽象化してある。
(詳しくは https://qiita.com/awa2/items/a7dbfa215365f46dd675)

* `valueChanges()`
    * get()したデータをJSON配列でそのままObservableとして流す
* `snapshotChanges()`
    * onSnapshot()を使って、メタデータを含む現在のデータを流す
    * `Observable<DocumentChangeAction[]>` が流れてくる
* `stateChanges()`
    * onSnapshot()を使って、メタデータ含む直近の変更を流す
    * `Observable<DocumentChangeAction[]>` が流れてくる

```
interface DocumentChangeAction {
  type: DocumentChangeType; // 'added' | 'modified' | 'removed';
  payload: {
    type: DocumentChangeType;
    oldIndex: number;
    newIndex: number;
    doc: {
      exists: boolean;
      ref: DocumentReference;
      id: string;
      metadata: SnapshotMetadata;
      data(): DocumentData;
      get(fieldPath: string): any;
    }
  }
}
```