LoginSignup
7
5

More than 3 years have passed since last update.

複数のプロジェクトのfirebase-adminを起動して、開発用に本番データの一部を移行する

Last updated at Posted at 2019-09-26

開発しているWebサービスで、本番データの一部を開発用に使いたいと思ったときの備忘録。
firebase-adminは複数のプロジェクトで使えるらしい。

開発用だけじゃなく、UIDを変更しながらのデータ移行などにも使えそう。

ローカル環境でfirebase-adminを使うための準備

準備の部分は、以前まとめたこちらを参照ください〜
- ローカルPCからfirebase-adminを使ってFirestoreを操作する(管理ツール) - くらげになりたい。

ソースはこんな感じ。

const admin = require("firebase-admin");  

// *** 移行元のプロジェクトの設定
const srcSA = require("./key/XXXXX.json");   // サービスアカウントの秘密鍵を取得
// firebase-adminの初期化
admin.initializeApp({ credential: admin.credential.cert(srcSA) }); 
const srcDB = admin.firestore();          // firestoreのインスタンスを取得

// ** 移行先のプロジェクトの設定
const destSA = require("./key/XXXXX.json");  // サービスアカウントの秘密鍵を取得
// ※同じadminを使って、別のAppを作成しないといけない※
// ※2つ目を初期化する場合は、"dest"など名前をつけないといけない※
const destAdmin = admin.initializeApp( { credential: admin.credential.cert(destSA) }, "dest");
const destDB = destAdmin.firestore();        // firestoreのインスタンスを取得

// ****************************
// * MAIN
// ****************************
async function main() {
  console.log(`***** START MAIN`);

  // 移行元からデータを取得
  const snaps = await srcDB.collection("data").get()
  const srcData = snaps.docs;

  for (let v of data) {
    try {
      // 移行先からデータを保存
      const destDataRef = destDB.collection("data").doc(v.id);
      await destDataRef.set(v.data());
    } catch (error) {
      console.errror(`Error: ${error}`, error);
    }
  }

  console.log(`***** END   MAIN`);
  process.exit(0);
}

main().then();

雛形はこんな感じ。

以前書いた以下の記事だと丸々移行するので、UIDが変わるとめんどくさいことになる。。

この方法であれば、

  • whereで一部のだけに絞り込んだり、
  • set()するときに、UIDを差し替えたり

できるので、開発用に使うにはよいかんじ。

注意1: 2つ目を初期化する場合は別の名前に

そのまんまコピペで2つのfirebase-adminを作るとエラーに。。
2つ目を初期化する場合は、"dest"など名前をつけないといけないいけないらしい。。

公式ドキュメントの「複数のアプリを初期化する」に書いてあった。

これで、2つのfirebase-adminが起動できるので、データ移行などもできそう(´ω`)

注意2: メモリを大量に使いそうな場合はオプションを指定

データが多く、メモリを大量に使いそうな場合は、
--max_old_space_sizeオプションを指定しないといけない。。

途中で失敗すると(読み込み/書き込み件数的に)悲しいことになるので、
大きめのサイズを指定しておくと良さそう。

node --max_old_space_size=8192 index.js 
注意3: 件数が多い場合は、limitを指定して再帰処理

大量のデータを一度に取得しようとすると、

Deadline Exceeded error

が出て怒られるので、少しずつ実行するのがよいかんじ。

const BATCH_SIZE = 300
async function moveData(lastItem) {
  // 移行元からデータを取得
  const colRef = srcDB.collection("data");
  let query = colRef.orderBy("createAt", "asc");
  if (lastItem != null) query = query.startAfter(lastItem.createAt);
  const snap = await query.limit(BATCH_SIZE).get();

  if (snap.docs.length === 0) return; // 0件なら終了する
  const srcData = snaps.docs;

  for (let v of data) {
    try {
      // 移行先からデータを保存
      const destDataRef = destDB.collection("data").doc(v.id);
      await destDataRef.set(v.data());
    } catch (error) {
      console.errror(`Error: ${error}`, error);
    }
  }

  // 最後の要素を渡して、そこから継続する
  await moveData(data[data.length - 1]);
}
// ****************************
// * MAIN
// ****************************
async function main() {
  console.log(`***** START MAIN`);

  await moveData(null);

  console.log(`***** END   MAIN`);
  process.exit(0);
}
注意4: 複数の場所に反映する場合は、batchやtransactionを使う

途中でエラーになる場合もあるので、batchやtransactionを使うとよさそう。

公式ドキュメントだと、このあたり
- トランザクションと一括書き込み  |  Firebase

  for (let v of data) {
    try {
      const batch = destDB.batch();

      // 移行先からデータを保存
      const destDataRef = destDB.collection("data").doc(v.id);
      batch.set(destDataRef, v.data());

      // 移行先からデータを保存: その2
      const destData2Ref = destDB.collection("data2").doc(v.id);
      batch.set(destData2Ref, v.data());

      // コミット
      await batch.commit();
    } catch (error) {
      console.errror(`Error: ${error}`, error);
    }
  }

ループ外で使うほうのもいい感じ。

ただ、一括で書き込めるドキュメント数は500までと制限があるので、
一度に書き込む範囲は適宜調整が必要。

1 回のトランザクションまたは一括書き込みでは、
最大500のドキュメントに書き込みを行うことができます。
トランザクションと一括書き込み  |  Firebase

まとめ

firebase-adminは複数のプロジェクトでも扱える。
部分的なデータ移行や一部を書き換えながらの移行もできる(´ω`)

ただ、件数が多かったり、複数の書き込みがある場合は、いろいろ必要。。

こんなのつくってます!!

積読用の読書管理アプリ 『積読ハウマッチ』をリリースしました!
積読ハウマッチは、Nuxt.js+Firebaseで開発してます!

もしよかったら、遊んでみてくださいヽ(=´▽`=)ノ

要望・感想・アドバイスなどあれば、
公式アカウント(@MemoryLoverz)や開発者(@kira_puka)まで♪

7
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
5