我想清理我的收藏数据。我有集合名称“团队”。它有数据和子集合名称“玩家”。
我已经通过 Firestore 的简单删除查询删除了 "teams" 文档,但我们知道我们不能通过删除主/祖先来删除子集合 (players)文档 ID。我们必须从 "players" 集合中获取所有文档,然后首先删除它们。 在我们应该删除祖先 (teams' doc) 文档之后,它就会清除所有集合。
无法从 "teams" 集合中获取那些孤立的文档。那么从集合中清除这些文档的方法是什么?
<块引用>~ 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 的代码,抱歉,我是新手,所以没有太多想法。我点击了运行按钮,但遇到了一些问题
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);
答案 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 中,文档和子集合不像文件系统文件和目录那样工作。所以总而言之,你不能删除不存在的东西。换句话说,因为该位置没有物理文档,因此您无法执行删除操作。