14
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ローカルPCでfirebase-adminを使って一括削除/一括更新する

Posted at

最近、Nuxt.js+Firebaseで作った積読を解消するWebアプリ「積読ハウマッチ」をリリースしました!!

そのときに、Firestoreのスキーマを一括変更したり、
不要なデータを一括削除したいと思ったときの備忘録。

ローカルPCでfirebase-adminを使うときの初期設定とかはこちらを参照

注意点

Firestoreでは、1度に実行できる更新処理の数に制限がある。

一括書き込みでは最大 500 件のオペレーションを実行できます

トランザクションと一括書き込み  |  Firebase

そのため、以下にも記載されている通り、
100件ごとなど、小さなバッチに分けて実行する必要がある。

メモリ不足エラーを避けるため、小さなバッチに分けてドキュメントを削除することをおすすめします。コレクション全体またはサブコレクションが削除されるまで、このプロセスを繰り返します。

Cloud Firestore からデータを削除する  |  Firebase

小さなバッチに分けて実行するソース

全体としてはこんな感じ。

登場する3つ

  1. main() ... メイン関数。実行したときに呼ばれる関数
  2. deleteAllUsers() ... ユーザを一括削除する関数。mainから呼ばれる
  3. executeBatch() ... 指定したバッチサイズで再帰的に実行する関数。deleteAllUsers()から呼ばれる

なお、コレクションusersのなかにあるドキュメントには、
作成日時のタイムスタンプcreateAtのドキュメントフィールドがある想定です。

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

// 配置したサービスアカウントの秘密鍵を取得
const serviceAccount = require("./key/XXXXX.json");

// firebase-adminを初期化
admin.initializeApp({ credential: admin.credential.cert(serviceAccount) });

// firestoreのインスタンスを取得
const db = admin.firestore();


/**
 * 一括実行処理の共通関数
 * @param {FirebaseFirestore.Firestore} db firestoreのインスタンス
 * @param {Number} limit 1回に実行するサイズ
 * @param {Function} queryFunc ドキュメントを検索するクエリを作成する関数。firestore.Queryを返す
 * @param {Function} executeFunc 削除や更新などを実行する関数。
 * @param {Object|undefined} last 検索でヒットした最後の要素。バッチサイズで繰り返す際に利用s
 */
async function executeBatch(db, limit, queryFunc, executeFunc, last) {

  // queryFuncを使って対象のドキュメントを取得
  const query = queryFunc(db, last);
  const items = await query.limit(limit).get();
  
  // ドキュメントが1つも見つからなければ、終了
  if (items.size === 0) return;

  // executeFuncを使ってbatchに削除/更新処理を追加&コミット
  const batch = db.batch();
  for (let i = 0; i < items.size; i++) {
    executeFunc(db, batch, items.docs[i]);
  }
  await batch.commit();
  
  // リストの最後の要素を取得して、再帰実行
  const lastItem = items.docs[items.size - 1].data();
  return await executeBatch(db, limit, queryFunc, executeFunc, lastItem);
}


/**
 * すべてのユーザを削除
 */
async function deleteAllUsers(db, limit) {
 // 検索部分の関数: 作成日時で昇順ソートして取得
 const queryFunc = (db, last) => {
    let query = db.collection("users").orderBy("createAt", "asc");
    if (!!last) query = query.startAfter(last.createAt);
    return query;
  };
  
  // 実行部分の関数: itemで該当のドキュメントを受け取るので削除
  const executeFunc = (db, batch, item) => {
    const docRef = db.collection("users").doc(item.id);
    batch.delete(docRef);
  };
  
  return await executeBatch(db, limit, queryFunc, executeFunc, undefined);
}

// ****************************
// * MAIN
// ****************************
async function main() {
  console.log(`***** START MAIN *****`);
  // バッチサイズを100件で実行
  const limit = 100;
  await deleteAllUsers(db, limit)
  console.log(`***** END   MAIN *****`);
}

main().then();

他の処理でも共通的に使えるようにexecuteBatch()では、
queryFuncexecuteFuncの2つの関数を引数で受け取れるようにしている。

なので他の処理などを追加するときは、deleteAllUsers()みたいなのを増やしていけばOK!!

これで一括削除やスキーマの更新もだいぶ楽に...(´ω`)

おわりに

Webサービスは運用しはじめると色々大変なので、管理ツールなども大事...
最近リリースしたこちらのアプリでも使ってます♪

■積んでる本の総額がわかる読書管理サービス
積読ハウマッチ

総額がわかると少しは積ん読してる本を読もうと思ったり♪
積読総額ランキングや人気の本などもあるので、よかったらあそんでもらえれば!!

積読ハウマッチは、Nuxt.js+Firebase+ZEIT Nowで作ってます♪

参考にしたサイト

14
9
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
14
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?