在Cloud Firestore中,为什么不能"单个批量"删除集合(可以使用实时数据库)?

Thi*_*ryC 16 firebase google-cloud-firestore

使用Firebase实时数据库,我们只需通过调用remove () 父节点就可以删除一个包含单个命令的大量项目(节点已被删除,所有节点也都是子节点).

但是根据Firestore的文档(https://firebase.google.com/docs/firestore/manage-data/delete-data#collections):
要删除一个Collection,我们必须编写一个将遍历所有它的批处理文件并逐一删除.

这根本没有效率.是因为Firestore是测试版还是在一次调用中删除整个节点(Collection)在结构上是不可能的?

Gil*_*ert 22

RTDB能够执行此操作,因为每个数据库都是单个区域的本地数据库.为了提供序列化视图,在您调用时remove(),数据库将停止所有其他工作,直到删除完成.

此行为导致了几个明显的中断:如果remove()调用必须删除大量数据,则所有其他活动在完成之前都会被有效锁定.因此,即使对于想要删除大量数据的RTDB用户,我们也建议以组的形式递归查找和删除文档(CLI,node.js).

另一方面,Firestore基于更传统的Google风格的存储基础架构,其中不同的密钥范围被动态分配给不同的服务器(存储实际上不受BigTable支持,但适用相同的原则).这意味着删除数据不再是单个区域操作,并且有效地使删除显示为事务性变得非常昂贵.Firestore事务目前仅限于100个参与者,这意味着任何非平凡的事务性批量删除都是不可能的.

我们正在研究如何最好地表现出一个批量删除的API,而没有承诺的事务行为.可以直接想象如何从移动客户端执行此操作,但正如您所看到的,如果我们所做的只是为您嵌入循环和批量删除,则效率不高.我们也不想让REST客户成为二等公民.

Firestore是一种新产品,还有很多事情要做.不幸的是,这还没有削减.虽然这是我们希望最终解决的问题,但我无法提供任何时间表.

与此同时,控制台和firebase命令行都提供了一种非事务性的方法,例如用于测试自动化.

感谢您对Firestore的理解和感谢!


Tho*_*hoe 6

我很高兴从Realtime Database重构我的Firestore应用程序,享受更短的代码和更简单的语法,直到我重构了delete()函数!要删除带有子集的文档:

  • 创建一个承诺数组.
  • get() 一个子集合,没有进一步的子集合.
  • 迭代forEach()函数以读取子集合中的每个文档.
  • 删除每个文档,然后将delete命令推送到promises数组中.
  • 继续下一个子集并重复此操作.
  • 使用Promise.all(arrayOfPromises)要等到所有的子集已被删除.
  • 然后删除顶级文档.

使用多层集合和文档,您可以将其作为一个函数,然后从另一个函数调用它以获得下一个更高层,等等.

您可以在控制台中看到这一点.要手动删除集合和文档,请删除最右侧的文档,然后删除最右侧的集合,依此类推.

这是我在AngularJS中的代码.仅当在子集合之前未删除顶级集合时,它才有效.

$scope.deleteClip = function(docId) {
if (docId === undefined) {
docId = $scope.movieOrTvShow + '_' + $scope.clipInMovieModel;
}
$scope.languageVideos = longLanguageFactory.toController($scope.language) + 'Videos';
var promises = [];
firebase.firestore().collection($scope.languageVideos).doc($scope.movieOrTvShow).collection('Video Clips').doc(docId).collection('SentenceTranslations').get()
.then(function(translations) {
  translations.forEach(function(doc) {
    console.log(doc.id);
    promises.push(firebase.firestore().collection($scope.languageVideos).doc($scope.movieOrTvShow).collection('Video Clips').doc(docId).collection('SentenceTranslations').doc(doc.id).delete());
  });
});
firebase.firestore().collection($scope.languageVideos).doc($scope.movieOrTvShow).collection('Video Clips').doc(docId).collection('SentenceExplanations').get()
.then(function(explanations) {
  explanations.forEach(function(doc) {
    console.log(doc.id);
    promises.push(firebase.firestore().collection($scope.languageVideos).doc($scope.movieOrTvShow).collection('Video Clips').doc(docId).collection('SentenceExplanations').doc(doc.id).delete());
  });
});
Promise.all(promises).then(function() {
  console.log("All subcollections deleted.");
  firebase.firestore().collection($scope.languageVideos).doc($scope.movieOrTvShow).collection('Video Clips').doc(docId).delete()
  .then(function() {
    console.log("Collection deleted.");
    $scope.clipInMovieModel = null;
    $scope.$apply();
  })
  .catch(function(error) {
    console.log("Remove failed: " + error.message);
  });
})
.catch(function(error){
  console.log("Error deleting subcollections: " + error);
});
};
Run Code Online (Sandbox Code Playgroud)

所有这些都是实时数据库中的一行.


Sha*_*ian 5

这是删除集合中所有文档的最快方法:混合使用python 删除集合循环python 批处理方法

def delete_collection(coll_ref, batch_size, counter):
    batch = db.batch()
    init_counter=counter
    docs = coll_ref.limit(500).get()
    deleted = 0

    for doc in docs:
        batch.delete(doc.reference)
        deleted = deleted + 1

    if deleted >= batch_size:
        new_counter= init_counter + deleted
        batch.commit()
        print("potentially deleted: " + str(new_counter))
        return delete_collection(coll_ref, batch_size, new_counter)
    batch.commit()

delete_collection(db.collection(u'productsNew'), 500, 0)
Run Code Online (Sandbox Code Playgroud)

这会以 500 个块为单位从集合“productNew”中删除所有文档,这是当前可以传递给提交的最大文档数。请参阅Firebase 写入和事务配额

您可以变得更复杂并处理 API 错误,但这对我来说很好用。