エクセルなどでまとめたデータを一括してFirestoreにインポート(アップロード)する方法です!
こちらの2つの記事を参考にしました。
Firestoreはじめ、色々と初心者ですが、そんな私でもなんとかできましたのでご安心ください。
ちなみにSwiftでiOSアプリ開発をしているものですが、swiftとか関係なく、Firestoreへのデータインポートのやり方はこの紹介するやり方になるようですね。
JSONデータを用意
エクセルなどのデータをJson形式に変換します。
こんなデータがあったとして、上部の「ファイル」→「ダウンロード」→csv形式を選択します。
その後このサイトでcsvからJSON形式に変換し、データはダウンロードしておきます。
参考にした記事では「アウトプットのオプションはHashを選択しておくこと」と記載があったので、Hashを選んでおいて変換します。
後日やった際にはアウトプットのオプションはArrayでないと、エクセル上での一番左の列がちゃんとインポートされなかったので、Arrayでやることをおすすめします。
ダウンロードした後はファイル名を「data.json」にしておきます。
Firebaseコンソールより、ServiceKeyをダウンロード
Firebaseのコンソールにて、プロジェクトの「ユーザーと権限」→「サービスアカウント」のページで新しい秘密鍵を生成します。
秘密鍵を生成すると、jsonのファイルがダウンロードされるので、こちらは「serviceAccountKey.json」という名前に変更しておきます。
データ登録用のディレクトリを作る
ローカルの好きな場所にフォルダを作って、ターミナルにてそのフォルダでnpm initを実行しFirebase SDKをインストールします。
今回はJsonという名前のフォルダを作りました。
$ mkdir Json
$ cd Json
$ npm init
$ npm install firebase-admin
特に何も情報は入力せず、EnterKeyをクリックし続けて、最後にyesと打ってインストール完了しました。
こうすると、node_modulesのフォルダと、package.jsonのファイルがJsonフォルダ内に生成されます。
ちなみにターミナルでnpmが反応しない場合は、まずHomebrewなどでnodeをインストールするところから始めてください。(そもそも私がそこからやらないとダメでした)
brew install node
serviceAccountKeyファイルとdataファイルを、Jsonフォルダに保存
先ほどダウンロードしておいたserviceAccountKey.jsonのファイルと、データのファイルdata.jsonを、Jsonフォルダへ移動しておきます。
フォルダ内はこんな形になっているはず。
Index.jsの作成
同フォルダ内でお好きなエディタでIndex.jsという名前のファイルを作成し、中身を下記のように書いて保存します。
collectionKeyの値・databaseURLの値、また後述のrestaurantNameの部分は個々で異なるのでご自身のものに設定してください。
collectionKeyは、どんな名前でコレクションを保存したいか、です。今回はrestaurantsというコレクションを作成したいのでその名前にしました。
databaseURLは、Firebaseコンソールから確認できます。
この場合、databseURLはhttps://tabemos-e5662.firebaseio.comになります。
const admin = require('./node_modules/firebase-admin');
const serviceAccount = require("./serviceAccountKey.json");
const data = require("./data.json");
const collectionKey = "restaurants"; //name of the collection
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://tabemos-e5662.firebaseio.com"});
const firestore = admin.firestore();
const settings = {timestampsInSnapshots: true};
firestore.settings(settings);
if (data && (typeof data === "object")) {
Object.keys(data).forEach(restaurantName => {
firestore
.collection(collectionKey)
.doc()
.set(data[restaurantName])
.then((res) => {
console.log("Document " + restaurantName + " successfully written!");
}).catch((error) => {
console.error("Error writing document: ", error);
});
});
}
restaurantNameの部分は、エクセルデータにおける一番左の列のヘッダー名を入れています。(レストランごとにドキュメントを作成したいという意図です。)
また各ドキュメントの名前を自動作成にしたい場合は、.doc()と記述します。
(各ドキュメントにrestaurantNameの名前を付けたい場合は、.doc(restaurantName)とします。)
↑こちら、間違いでした。ご指摘いただきありがとうございます。(ちなみに、この .doc(restaurantName)でインポート実行すると、ドキュメント名は1, 2, 3などの数字になりました。)
各ドキュメントにrestaurantNameの名前を付けたい場合は、.doc(data[restaurantName].restaurantName) とします。
データ保存を実行
最後に
node index.js
を実行します。
うまくいくと、下記のようなメッセージが出てきます。
Firebaseの方にも追加されていて、大成功です。
既存のコレクションにも追加可能
ちなみに今回は既にあるrestaurantsのコレクションにデータを追加してみましたが、それでもうまく行きました。
新規にコレクションを作ってデータを追加する形でも、もともとあるコレクションにデータを追加する形でも、どちらも柔軟にデータ追加できるようです。
コメント
firestore初心者で、大変参考になりました。ありがとうございます。
各ドキュメントにrestaurantNameの名前を付けたい場合ですが、記載されている通りですと正しく命名されないかと思います。
(ターミナルのスクリーンショットでもrestaurantNameがただの数字になっています)
上記を修正するには、
~前略~
Object.keys(data).forEach(hoge => {
~中略~
.doc(data[hoge].restaurantName)
のようにすれば良いかと思います。
不慣れなもので見辛いコメントになってしまい申し訳ありません。
読んでいただきありがとうございます!コメント、ご指摘大変ありがたいです。
確かに、やってみたところ今書いてあるやり方だとドキュメント名は数字になってしまいますね。
ご指摘いただいた方法で、ちゃんとrestaurantNameの名前でドキュメント名に反映されるようになりました!!ありがとうございます!内容も修正するようにいたします。