Firestore 删除不存在的祖先文档和子集合

时间:2021-06-24 10:15:12

标签: javascript node.js firebase google-cloud-firestore google-cloud-functions

我想清理我的收藏数据。我有集合名称“团队”。它有数据和子集合名称“玩家”

我已经通过 Firestore 的简单删除查询删除了 "teams" 文档,但我们知道我们不能通过删除主/祖先来删除子集合 (players)文档 ID。我们必须从 "players" 集合中获取所有文档,然后首先删除它们。 在我们应该删除祖先 (teams' doc) 文档之后,它就会清除所有集合。

无法从 "teams" 集合中获取那些孤立的文档。那么从集合中清除这些文档的方法是什么?

I want to delete all the document (italic)

<块引用>

~ PS:我创建了一个 firebase 云函数来删除子集合文档,同时删除祖先文档。

exports.deleteOrphanedTeamsDoc = functions.firestore
  .document('teams/{teamID}')
  .onDelete(async (snap, context) => {
    var teamID = context.params.teamID;
    console.log("Deleted teamID --->>> " + teamID);

    const store = admin.firestore();
    var teamsPlayer = await store.collection('teams').doc(teamID).collection('players').get()

    teamsPlayer.docs.forEach(async(val) => {
      await store.collection('teams').doc(teamID).collection('players').doc(val.id).delete();
    });
  });

所以在上面代码的帮助下,我也可以删除带有子集合的新团队 docID。

但是我的“团队” 集合中所有可用的孤立文档呢?

<块引用>

更新 1:

我尝试了 Renaud Tarnec 的代码,抱歉,我是新手,所以没有太多想法。我点击了运行按钮,但遇到了一些问题

enter image description here

6:46:13.625 pm
scheduledFunction
Function execution took 12608 ms, finished with status: 'error'
6:46:13.622 pm
scheduledFunction
at processTicksAndRejections (internal/process/task_queues.js:97:5)
6:46:13.622 pm
scheduledFunction
at runMicrotasks (<anonymous>)
6:46:13.622 pm
scheduledFunction
at /workspace/index.js:161:53
6:46:13.622 pm
scheduledFunction
ReferenceError: promises is not defined 
6:46:01.018 pm
scheduledFunction
Function execution started

我认为问题出在 ReferenceError: promises is not defined

const parentsSnapshotsArray = await Promise.all(promises);

2 个答案:

答案 0 :(得分:2)

<块引用>

但是我的“团队”中可用的所有孤立文档呢? 收藏。

正如您所提到的,您的云函数不会为已删除的 teams 文档触发。

要删除孤立的 player 文档,您可以做的是每 X 分钟/小时运行一次预定的 Cloud Function。

以下 Cloud 函数使用 CollectionGroup query 获取所有 player 文档并删除它们。请注意,您需要为查询创建 Firestore 索引。还要注意我们如何使用 Promise.all() 来在所有异步工作完成后返回一个唯一的 Promise;这是 correctly manage the lifecycle of your Cloud Function 的关键。

exports.scheduledFunction = functions.pubsub.schedule('every 5 minutes').onRun((context) => {

    const playersRef = admin.firestore().collectionGroup('players');
    const playersSnap = await playersRef.get();

    const promises = [];
    playersSnap.forEach((doc) => {
        promises.push(doc.ref.delete());
    });
    return Promise.all(promises)

});

现在,我们需要添加一个额外的业务逻辑。 player 文档应被删除仅当父 team 文档不存在时

以下代码应该可以解决问题(未经测试):

exports.scheduledFunction = functions.pubsub.schedule('every 5 minutes').onRun(async (context) => {

    const playersRef = admin.firestore().collectionGroup('players');
    const playersSnap = await playersRef.get();

    const docParentIdsToDelete = [];

    const docParentIdsTreated = [];
    const promisesParentDocs = [];
    playersSnap.forEach((doc) => {
        const parentTeamRef = doc.ref.parent.parent;
        const parentTeamId = parentTeamRef.id;
        if (docParentIdsTreated.indexOf(parentTeamId) < 0) {
            // We need to check if the parent exists
            promisesParentDocs.push(parentTeamRef.get());
            docParentIdsTreated.push(parentTeamId);
        }
    });

    const parentsSnapshotsArray = await Promise.all(promisesParentDocs);

    parentsSnapshotsArray.forEach(snap => {
        if (!snap.exists) {
            // The parent team doc DOES NOT exist. It is shown in italic in the Firebase console.
            // => We need to delete the players child docs
            docParentIdsToDelete.push(snap.id);
        }
    });
    
    const promisesDeletion = [];
    playersSnap.forEach((doc) => {
        const parentTeamId = doc.ref.parent.parent.id;
        if (docParentIdsToDelete.indexOf(parentTeamId) > -1) {
            // We need to delete the player doc
            promisesDeletion.push(doc.ref.delete());
        }
    });
    
    return Promise.all(promisesDeletion);
    
});

基本上,我们首先获取所有 player 文档。然后我们循环检查父 team 文档是否存在(使用数组来最小化查询次数)。如果它不存在,我们将其 ID 推送到数组 => 需要删除 player 子文档。然后我们再次在 player 文档上循环并删除所需的文档(再次通过将删除承诺推送到传递给 Promise.all() 的数组)。可能有一些优化代码和减少循环次数的空间,但逻辑是存在的(如果我没有做错:-))。

答案 1 :(得分:1)

Firebase 控制台通过那些斜体 文件表明,这些文件实际上并不存在。这些文档不存在,要么是因为您没有创建它们,要么是您明确删除了它们。所以这些文档仍然显示,因为它们下面有一个子集合。所以基本上文档的 ID 会以某种方式保留,如果你以后需要做一些操作。

要记住的一件事是,在 Cloud Firestore 中,文档和子集合不像文件系统文件和目录那样工作。所以总而言之,你不能删除不存在的东西。换句话说,因为该位置没有物理文档,因此您无法执行删除操作。

相关问题