🦥

csvファイルをFirestoreにimportする

2020/11/22に公開

次世代モバイルオーダーサービス『 SmartDish 』を運営しております、根性タフなmoroです。🦥 @tweet

『 SmartDish 』はNocodeで作られているアプリで、2020年9月1日にリリースしました。ですが、当月の中旬頃から Flutter/Firebase で作られたアプリに切り替えるために開発を始め、その際に行ったデータ移行について共有しようと思います

csvファイルにあるデータをFirestoreに書き込むやり方です。

なぜ、Nocode で開発・リリースしたものを Flutter/Firebase に置換しているのかは、ビジネス面も踏まえて別の記事で話します。

1. clone repository

GitHub や Bitbucket などで作成した repository をエディター(Android Studio や Visual Studio Code など)で開きます。

2. 3つのファイルを作成

空っぽのプロジェクトに2つのファイルを作成します。

package.json
package.jsonは、必要なパッケージを宣言するため

firebase-adminsdk.json
firebase-adminsdk.jsonは、どのFirebaseプロジェクトに書き込みするのか情報を記したもの

index.js
index.jsは、読み込んだcsvファイルをFirestoreの型に置き換える部分

3. 全体像

そもそもなぜ、csvファイルをFirestoreに書き込みたいかというと『 SmartDish 』の場合、登録店舗さんのお店、メニュー情報、写真などの情報が大量にあり、ぽちぽち手入力でデータを入力していくには効率が悪いので、わざわざコードを書いて、データを書き込んでいます。

苦労したところでいうと、それぞれのお店のそれぞれのメニューにオプションメニューがあり、そのオプションメニューも必須オプション・任意オプションという感じで構造が深くなる部分が少し苦戦しました。

大量のデータを移行する必要がなければぽちぽちで良いと思います。

話が逸れたので戻します。全体像をざっくり話すと、、、、

(1)同じプロジェクト(ディレクトリ)の中に、移行したい csv ファイルを入れる、その csv ファイルをFirestoreにどのような型で書き込みしたいか書いたファイル(index.js)を作成。

そして、そこにはもう一つファイルが必要で、

(2)それが先ほど作成した package.json です。このファイルでは書き込む際に使うコマンドだったり Firestore  を書き込むために必要なパッケージを宣言しときます。宣言して、そのパッケージをインストールするためのコマンドを打つと自動的にそのパッケージがプロジェクト内にインストールされます(package-lock.json)。

(3)firebase-adminsdk.jsonでは、書き込みしたいFirebaseの情報を記します。

これができてようやく、データが書き込める準備ができて

(4)ターミナルでコマンドを打つだけ!

(5)移行完了

ここでネックになるのがお分かりの通り、index.json です。私は開発が始まってから初めて javascript を触り少し詰まりましたので参考になれば幸いです。

ここから共有するコードは、そのままコピペで使えます

4. csvファイルをプロジェクトに入れる

プロジェクト直下に "csv" という名前のディレクトを作成します。作成したら、その中にドラッグ&ドロップで書き込みしたいcsvファイルを入れます。何個でも大丈夫です。

5. package.json

私の場合、dev、stg、prodと3つのプロジェクトがあり、それぞれにデータの書き込みをしたいので、"scripts"でプロジェクトの切り替えができるようにしています。 "dev"、"stg"、"prod" と書かれている部分は、自由に書き換えて大丈夫です。

 "main": "index.js",
 "scripts": {
   "dev": "node index.js dev",
   "stg": "node index.js stg",
   "prod": "node index.js prod",
 },
 "dependencies": {
   "csv-parser": "^2.3.3",
   "firebase-admin": "^9.2.0",
   "fs": "^0.0.1-security"
 },
 "license": "MIT"
}

1つのプロジェクトの場合は、こちらのコードで大丈夫です。

{
 "main": "index.js",
 "dependencies": {
   "csv-parser": "^2.3.3",
   "firebase-admin": "^9.2.0",
   "fs": "^0.0.1-security"
 },
 "license": "MIT"
}

6. firebase-adminsdk.json

以下のコードの<>の6つを自分のプロジェクトのものに置き換えて、ファイルにコピペします。

{
 "type": "service_account",
 "project_id": "<project-id>",
 "private_key_id": "<key-id>",
 "private_key": "-----BEGIN PRIVATE KEY-----\n<private-key>\n-----END PRIVATE KEY-----\n",
 "client_email": "<service-account-email>",
 "client_id": "<client-id>",
 "auth_uri": "https://accounts.google.com/o/oauth2/auth",
 "token_uri": "https://oauth2.googleapis.com/token",
 "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
 "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/<service-account-email(client_emailと同じ)>"
}

こちらの公式ドキュメントにあるように、自分のプロジェクトのidなどはGCPで確認できます。

https://cloud.google.com/iam/docs/creating-managing-service-account-keys

複数のプロジェクトにデータを書き込みたい場合は、

このようにして5の scripts で書いた名前と同じディレクトリ名を作成して、その中にそれぞれ firebase-adminsdk.json ファイルを作成します。中身もそれぞれのプロジェクトごとに変更します。

1つのプロジェクトの場合、firebase-adminsdk.json ファイルはプロジェクト直下に作成します。

7. index.json

このファイルでは、

  1. Firestore を初期化する
  2. csv ファイルを読み込む
  3. Firestore スキーマーを構築する
  4. Firestore に書き出す

この4つの手順を追ってコードを記述します。

① Firestore を初期化する

const admin = require('firebase-admin');
const serviceAccount = require(`./secret/${env}/smartdish-firebase-adminsdk.json`);
const databaseURL = (env === 'dev' || env === 'stg' || env === 'prod') ? `https://smartdish-${env}.firebaseio.com` : `https://smartdish.firebaseio.com`
 admin.initializeApp({
   credential: admin.credential.cert(serviceAccount),
   databaseURL: databaseURL
 });
const db = admin.firestore()​

このコードでFirestore を初期化し、Firestore にデータを書き込んだり、書き込むプロジェクト先をターミナルで打つコマンドで切り替えられたりします。

const databaseURL = (env === 'dev' || env === 'stg' || env === 'prod') ? `https://smartdish-${env}.firebaseio.com` : `https://smartdish.firebaseio.com`

env === 'dev'の部分は、5の scripts で宣言した名前で切り替えています。

この部分は、複数プロジェクトでデータを書き込むためなので、1つのプロジェクトであれば、

const databaseURL = `https://<プロジェクト名>.firebaseio.com`;

こちらのコードでできます。

② csv ファイルを読み込む

 const test = await loadCsv('./csv/<ファイル名>.csv')

"test" の部分は変数名なので何でも大丈夫です。

③Firestore スキーマーを構築する

csv ファイル(②で読み込んだファイル)がこのようにデータが入っているとする場合、

名前 年齢
Ayumi 30
Ryo 20
Ann 15
function buildTestcheme(test) {
 const testList = []
 for (const testData of test) {
    testList.push(
      {
       name: testData['名前'],
       age: parseInt(testData['年齢']),
      }
    )
 }
 return testList
}

testSchemes = buildTestcheme(test)

読み込んだデータを使って、スキームを変更します。
Firestoreのドキュメントに、"name"(String)と "age"(number)2つのフィールドを書き出したい場合の関数です。

ここのスキームの変更方法で array型、geoPoint型、セカンドコレクションに特定の年齢の人だけドキュメント作成したいなどといった場合は少し複雑になります。

もしそこが知りたい方がいれば、連絡もらえればコードの共有します!🙋🏽‍♀️

④Firestore に書き出す

const batch = db.batch()
const testCollection = db.collection('tests')
testSchemes.forEach((testScheme) => {
    const doc = testCollection.doc()
    batch.create(doc,testcheme.data)
});
await batch.commit()

こちらのコードでは、先ほどスキームを変更したデータを batch に作成して、最後の行の .commit() で特定のコレクションに書き込みを行っています。

8. ターミナルでコマンドを打つ

npm install

こちらのコマンドは5で宣言したパッケージをローカルにインストールするコマンドです。インストールが成功すると、package-lock.jsonが作成されます。

npm install <パッケージ名>

もしうまく行かない場合は5で宣言したパッケージ名を一つずつインストールすることもできます。

firebase login

ターミナルで firebase に login します。メールアドレスとパスワードを入力します。

npm run <script名>

この script名 は、5で宣言した名前を入力します。この記事の場合だと、”dev”、”stg”、”prod”、この3つのどれかを打ちます。
ここでプロジェクトごとに切り替えができます。

以上が、csvファイルをFirestoreにimportするやり方でした。この記事では、 index.js はすごく簡単に書いたのですが、実際の『SmartDish』のデータでは、より複雑なコードで書いてました。

もし同じような状況の人がいればコードの共有をするので気軽に声かけてください!✌🏽

何か記事のリクエストや『SmartDish』のこの機能どうなってるのというのがあればぜひコメントお願いします。☺️

Discussion