Firestoreにスプレッドシートで作ったマスターデータをインポートする方法

# 😇やりたいこと
- スプレッドシートで作ったデータをFirestoreにインポートしたいぜ！

# 🫠ポイント
- インポートするためにはFirestoreのインポート書式に沿ったJSONを用意する必要あり
- スプレッドシートはCSVにはエクスポートできるけど、JSONにはエクスポートできない
- JSONにするにはGAS(Google Apps Script)を書く必要あり
- できたJSONはnodeコマンドを叩いてインポートする必要あり

# 👨‍🍳用意するもの
- nodeのインストール
- npmのインストール
- npmでnode-firestore-import-exportをインストール
- Firestoreの管理画面で発行したnode用の秘密鍵
- スプレッドシートで吐き出したJSON

# 📔手順
## 手順1:スプレッドシートでデータを用意する

例：
スプレッドシート名：適当
sheet名：foods

| ID | name | category |
| -------- | -------- | -------- |
| 1     | tomato     | vegetables     |
| 2     | tuna     | fish     |
| 3     | beef     | meat     |

# 手順2:gasを作成する
- 作成したスプレッドシートの画面で、拡張機能 > App Script を選択
- コード.gsに下記の内容を貼り付け
- 保存
- 初めて実行する際は権限の許可を確認されるので許可する
- 実行
- スプレッドシートの画面に戻るとダウンロードリンクが表示されているのでクリックするとダウンロードされる
- 別のシートをダウンロードしたい場合は、別のシートを開いた状態で再度実行ボタンをクリックすること

```js
function downloadAsJSON() {
  // スプレッドシートからデータを取得
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const sheetName = sheet.getName();
  const [headers, ...rows] = sheet.getDataRange().getValues();

  // データをオブジェクトに整形
  const data = buildDataObject(headers, rows);

  // 最終的なJSONオブジェクトの構築
  const jsonObject = buildJsonObject(sheetName, data);

  // JSON文字列に変換
  const jsonString = JSON.stringify(jsonObject, null, 2);

  console.log(jsonString);
  
  // Blobを作成してダウンロードリンクを生成
  createDownloadLink(jsonString);
}

function buildDataObject(headers, rows) {
  const data = {};
  for (const row of rows) {
    const rowKey = row[0]; // 最初の列の値をキーとする
    const record = {};
    for (let j = 1; j < headers.length; j++) {
      record[headers[j]] = row[j];
    }
    data[rowKey] = record; // キーをオブジェクトのプロパティとして設定
  }
  return data;
}

function buildJsonObject(sheetName, data) {
  // firestoreのフォーマットに整形
  return {
    __collections__: {
      [sheetName]: data,
    },
  };
}

function createDownloadLink(jsonString) {
  const blob = Utilities.newBlob(jsonString, 'application/json', 'sheet_data.json');
  const url = DriveApp.createFile(blob).getDownloadUrl();
  const htmlOutput = HtmlService.createHtmlOutput(`<a href="${url}" target="_blank">Download JSON</a>`);
  SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Download JSON');
}
```

:::note warn
メモ
buildJsonObject()にて、firestoreのフォーマットに合わせてますので、変更があった場合はこちらを調整してください。
:::

# 手順3:ツールを用意する
- nodeをインストールする
    - https://nodejs.org/en
- npmをインストールする
    - nodeをインストールすると自動でインストールされている
- node-firestore-import-exportをインストール

```
npm install -g node-firestore-import-export
```

## 手順4:firestoreの認証ファイルをゲットする
- プロジェクトの管理画面を開く
- 設定を開く
- サービスアカウントを開く
- Admin SDK 構成スニペットでNode.jsを選択
- 「新しい秘密鍵を生成」ボタンをクリック
- ダウンロードしたファイル名は適当に変更してok

![スクリーンショット 2024-08-04 10.36.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63060/9d2fee75-c7be-b063-6aad-488786c20240.png)

## 手順5:ターミナルでコマンドを叩く

インポートしたいとき

```
firestore-import -a serviceAccountKey.json -b hogehoge.json
```

エクスポートしたいとき

```
firestore-export -a serviceAccountKey.json -b hogehoge.json
// エクスポートする場合、エクスポートした場合のファイル名を自分で決める
```

| オプション | 説明 |
|-----|------|
| -V  | バージョン番号を出力 |
| -a  | Google Cloudアカウント認証情報JSONファイルのパス。|
| -b  | バックアップファイルの名前。（例：backups/full-backup.json） |
| -n  | インポートを開始するデータベースノードのパス（コレクションである必要があります）。 （例：collectionA/docB/collection）|


:::note
メモ
インポートする際、同じ階層に既にデータがある場合、重複するコレクション名がある場合は上書き、重複するコレクション名がない場合は追加扱いになる。
そのため、特定のコレクションのみのJSONを用意すれば、コレクション単位でのインポートが可能。
:::

以上