【Swift】FireStoreで複数のドキュメントを削除

どうも、ねこきち(@nekokichi1_yos2)です。

 

FireStoreにあるドキュメントを削除するには、

Firestore.firestore().collection("co1").document("do1").delete()

を使えばいいだけです。

 

しかし、複数のドキュメント(もしくはコレクション)を1度に削除するとしたらどうでしょう?

 

まず、Firebaseのデータを扱うメソッドって非同期処理なので、実行するタイミングも実行時間もバラバラです。

 

もし、用意したドキュメントの階層URLを用意して、for文で1つずつ削除した場合、全部のドキュメントを削除するまでどれくらいかかるかわかりません。

 

また、特定のコレクションを削除したい場合も同様で、階層下のドキュメントを全て削除しなければなりません。

 

(参考)

stackoverflow.com

 

そこで、WriteBatch、の出番です。

 

 

 

解説

 

FireStoreには、

  • コレクションを指定して削除できない
  • ドキュメントを持つドキュメントは削除できない

の制限があります。

 

なので、階層を丸ごと全削除!!..なんてことは出来ません。

 

その上で、WriteBatchを使えば、簡単に削除が行えます。

 

WriteBatchの書き方

 

WriteBatchとは、指定したドキュメントに対し一括書き込みができる処理です。

 

また、指定するドキュメントは複数でもOK。

 

必要な変数は、

  • バッチ
  • 階層URL

 

必要な処理は、

  • バッチに登録
  • バッチをコミット

 

補足として、バッチに登録する際、追加・更新・削除、を指定できます。

batch.setData(["test" : 1], forDocument: ref)
batch.updateData(["test" : 2], forDocument: ref)
batch.deleteDocument(ref)

 

 

注意点として、バッチはドキュメントを扱うので、コレクションを指定すると、下記のエラーが出る。

Cannot convert value of type 'CollectionReference' to expected argument type 'DocumentReference'

 

参考:https://cloud.google.com/firestore/docs/manage-data/transactions#batched-writes

 

WriteBatchの活用方法

 

WriteBatchはバッチに登録さえすれば、どれだけの数だろうと、全てのドキュメントに対して処理を適用できます。

(ただし、1度のコミットでは500個まで)

 

なので、バッチに登録する際は

  • ドキュメントのIDを取得
  • for文で取得したIDを次々に登録
  • 一括でコミット

が手っ取り早いです。

for documentID in documentIDs {
    let ref = db.collection(????).document(????)
    batch.deleteDocument(ref)
}

 

ソースコード

 

import UIKit
import Firebase

class test1: UIViewController {
    
    let db = Firebase.Firestore.firestore()
    
    @IBAction func saveData(_ sender: Any) {
        //ドキュメントを保存
        db.collection("co1").document("do1").collection("co2").document("do2").setData(["test":1])
    }
    
    @IBAction func deleteData(_ sender: Any) {
        writeBatch()
    }
    
    func writeBatch() {
        let db = Firestore.firestore()
        let ref = db.collection("co1").document("do1").collection("co2").document("do2")
        //バッチを生成
        let batch = db.batch()
        //バッチに階層refの削除を登録
        batch.deleteDocument(ref)
        //バッチをコミット
        batch.commit() { err in
            if let err = err {
                print("エラー:\(err)")
            } else {
                print("削除完了")
            }
        }
    }
    
}