如何从Android删除Firestore收藏

时间:2018-09-03 01:16:54

标签: android firebase google-cloud-firestore

问题

我正在寻找一种临时解决方案,以从客户端删除集合,以证明我的概念。我最终将按照建议将其重构到服务器上。

我要添加功能以删除所有特定Firestore用户的帐户信息,包括他们在应用程序中保存的内容集。对于Firestore documentation,没有建议的客户端执行此操作的方法,因为建议在服务器上进行处理。

2 个答案:

答案 0 :(得分:3)

要从Cloud Firestore数据库中删除整个集合或子集合,您需要检索集合或子集合中的所有文档并将其删除。

如果集合较大,则可能希望分批删除文档,以避免内存不足的错误。因此,您应该重复此过程,直到删除了整个集合或子集合。

即使Firebase团队不建议执行删除操作,因为该操作具有负面的安全性和性能影响,您仍然可以执行此操作,但只能用于small collections。如果您需要删除整个Web集合,请仅从受信任的服务器环境中删除。

对于Kotlin,请使用以下功能:

private fun deleteCollection(collection: CollectionReference, executor: Executor) {
    Tasks.call(executor) {
        val batchSize = 10
        var query = collection.orderBy(FieldPath.documentId()).limit(batchSize.toLong())
        var deleted = deleteQueryBatch(query)

        while (deleted.size >= batchSize) {
            val last = deleted[deleted.size - 1]
            query = collection.orderBy(FieldPath.documentId()).startAfter(last.id).limit(batchSize.toLong())

            deleted = deleteQueryBatch(query)
        }

        null
    }
}

@WorkerThread
@Throws(Exception::class)
private fun deleteQueryBatch(query: Query): List<DocumentSnapshot> {
    val querySnapshot = Tasks.await(query.get())

    val batch = query.firestore.batch()
    for (snapshot in querySnapshot) {
        batch.delete(snapshot.reference)
    }
    Tasks.await(batch.commit())

    return querySnapshot.documents
}

答案 1 :(得分:2)

更新的解决方案

Firebase团队记录在案的Delete Collections and Subcollections解决方案更加可靠和安全,因为它是在客户端外部的Cloud Function中实现的。我已经相应地重构了解决方案。

/**
* Initiate a recursive delete of documents at a given path.
*
* This delete is NOT an atomic operation and it's possible
* that it may fail after only deleting some documents.
*
* @param {string} data.path the document or collection path to delete.
*/

exports.deleteUser = () => functions.runWith({timeoutSeconds: 540, memory: '2GB'})
   .https.onCall((data, context) => {
    if (context.auth.uid !== data.userId)
      throw new functions.https.HttpsError(
        'permission-denied','Must be an administrative user to initiate delete.');
    const path = data.path;
    console.log(`User ${context.auth.uid} has requested to delete path ${path}`);

    return firebase_tools.firestore.delete(path, {
      project: process.env.GCLOUD_PROJECT,
      recursive: true,
      yes: true,
      token: functions.config().fb.token
    }).then(() => { return { path: path }; });
});

旧解决方案(在客户端执行)

传递给该方法的是用户Collection的引用以及要处理的批次大小。

fun deleteCollection(collection: CollectionReference, batchSize: Int) {
    try {
        // Retrieve a small batch of documents to avoid out-of-memory errors/
        var deleted = 0
        collection
                .limit(batchSize.toLong())
                .get()
                .addOnCompleteListener {
                    for (document in it.result.documents) {
                        document.getReference().delete()
                        ++deleted
                    }
                    if (deleted >= batchSize) {
                        // retrieve and delete another batch
                        deleteCollection(collection, batchSize)
                    }
                }
    } catch (e: Exception) {
        System.err.println("Error deleting collection : " + e.message)
    }
}