FirestoreへJSONをインポートする方法

#はじめに
Firebaseで現在(2018年4月)β版で稼働しているCloudFireStore、既存のRealtimeDatabaseより強力で高性能らしいがコンソールで操作できることが少ない。
コンソールで手動で入力するかスクリプトを書いてアップロードするしか方法がない。
Realtimeatabaseのようにjsonからインポートするために２時間ほど四苦八苦したまとめ。
基本は[このサイト](https://hackernoon.com/filling-cloud-firestore-with-data-3f67d26bd66e)を参考にした。

####環境について
MacOS High Sierra
Node v9.11.1

#データ構造について
Firestoreは三段階のデータ構造を持っている。

1. Collection - Documentを格納している
2. Document - CollectionもしくはFieldを格納している
3. Field - KeyとValueのペア

Collectionは中身のDocumentを全て削除しないと消えない

これを理解せずにCollectionを乱立させた結果、DBがぐちゃぐちゃになったので注意。

#データ管理用のアカウントを作る
FirebaseコンソールからProjectOverviewの隣の設定 --> Users and Permission
--> Service Account --> Create Service Account

Service account name は　data-transfer （なんでもいい）
Role は　Project --> Editor
Furnish a new private key にチェック、Key type はJSON

アカウントを作ると管理用アカウントの鍵がダウンロードされる。
名前をservice-key.jsonに変えておく

#用意
Firestoreデータ管理用のフォルダを作ると楽
firebase-adminをインストールする
`node install firebase-admin`

フォルダ内
- node_modules
- service-key.json
- data.json(インポートしたいデータ)
- json-to-firestore.js(後述)

#JSONからアップロード
###パターン１:複数のCollectionを作る場合。
```data.json
{
    "CollectionName1": {
        "DocumentName1": {
            "key1": "value1"
        }
    }
}
```
```json-to-firestore.js
const admin = require('./node_modules/firebase-admin');
const serviceAccount = require("./service-key.json");

const data = require("./data.json");

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: "https://<YOUR_DB>.firebaseio.com"
});

data && Object.keys(data).forEach(key => {
    const nestedContent = data[key];

    if (typeof nestedContent === "object") {
        Object.keys(nestedContent).forEach(docTitle => {
            admin.firestore()
                .collection(key)
                .doc(docTitle)
                .set(nestedContent[docTitle])
                .then((res) => {
                    console.log("Document successfully written!");
                })
                .catch((error) => {
                    console.error("Error writing document: ", error);
                });
        });
    }
});

```
###パターン２:一つのCollectionを作る場合
```data.json
{
    "DocumentName1": {
        "key1": "value1"
    }
}
```
```json-to-firestore.js
const admin = require('./node_modules/firebase-admin');
const serviceAccount = require("./service-key.json");

const data = require("./data.json");

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: "https://<YOUR_DB>.firebaseio.com"
});

data && Object.keys(data).forEach(key => {
    const nestedContent = data[key];

    admin.firestore()
        .collection('<COLLECTION NAME>')
        .doc(key)
        .set(nestedContent)
        .then((res) => {
            console.log("Document successfully written!");
        })
        .catch((error) => {
            console.error("Error writing document: ", error);
        });
});

```
###パターン３:深くネストされたJSONの場合
[こちら](https://stackoverflow.com/questions/46640981/how-to-import-csv-or-json-to-firebase-cloud-firestore)に使えそうなコードがありました。
Node 8.0 以降が必要になります。
検証したら書きます。

#終わりに
Firestoreはまだβ版ですがこれから使われることも増えると思います。
そのうちJSONのインポートもコンソールで出来るようになる(なればいいな)かもしれないのでそれまではこの方法を使いましょう。