如何从Android中删除Firestore集合

5

问题

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

我正在添加一个函数,用于删除特定Firestore用户的所有帐户信息,包括应用程序中保存的内容集合。根据Firestore文档,没有建议从客户端处理此操作,因为推荐在服务器上处理。

3个回答

5
要从云端Firestore数据库中删除整个集合或子集合,您需要检索集合或子集合中的所有文档并将它们删除。
如果您有更大的集合,请分批删除文档以避免内存不足错误。因此,您应该重复此过程,直到删除整个集合或子集合为止。
即使Firebase团队不推荐删除操作,因为它会产生负面安全和性能影响,但您仍然可以这样做,但仅针对小型集合。如果您需要从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
}

我正在使用REST API来操作我的集合,因为我想要为此构建一个Rust crate。要从Cloud Firestore数据库中删除整个集合或子集合,您需要检索集合或子集合中的所有文档并将它们删除。这也适用于我的情况。谢谢。 - Victor Oliveira

3

更新的解决方案

Firebase团队的删除集合和子集合文档中提供的解决方案更加可靠和安全,因为它在客户端之外的云函数中实现。我已相应地重构了我的解决方案。

/**
* 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)
    }
}

如何在Android中使用deleteUser函数? - Pokhraj Sah
据我在2018年所记得的,根据文档,@PokhrajSah,这是不推荐的。 - AdamHurwitz
这个删除操作不是原子操作,可能会引起问题,对吗? - Richardson

0
我有一个像这样的数据库,我将删除add_to_cart集合,如下所示:

I have my DB like this

   Query query = firestore.collection("add_to_cart");

   query.addSnapshotListener((snapshots, error) -> {
            if (error != null) {
                // Handle error
                Log.e("ABCD", error.getMessage());
            } else {
                // Iterate over the documents

                for (QueryDocumentSnapshot document : snapshots) {
                    // Do something with the document data
                    Log.e("ABCD -->", document.getId());
                    firestore.collection("add_to_cart").document(document.getId()).delete().addOnSuccessListener(aVoid -> {
                        // The snapshot was deleted successfully
                        Toast.makeText(CheckOutActivity.this, "Order placed successfully", Toast.LENGTH_SHORT).show();
                    }).addOnFailureListener(e -> {
                        // The snapshot could not be deleted
                        Log.e("TAG", "Error deleting snapshot  -->" + e.getLocalizedMessage());
                    });

                }
            }
        });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接