[英]Firestore delete non-existent ancestor documents and sub-collection
我想清理我的收藏數據。 我有集合名稱"teams" 。 它有數據和子集合名稱“玩家” 。
我已經通過 Firestore 的簡單刪除查詢刪除了“團隊”文檔,但正如我們所知,我們無法通過刪除主/祖先 docID 來刪除子集合(玩家) 。 我們必須從“玩家”集合中獲取所有文檔,然后首先刪除它們。 之后我們應該刪除祖先(團隊的文檔)文檔,以便清除所有集合。
不可能從“團隊”集合中獲取那些孤立的文檔。 那么從集合中清除這些文檔的方法是什么?
~ 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
at
const parentsSnapshotsArray = await Promise.all(promises);
但是我的“團隊”集合中所有可用的孤立文檔呢?
正如您所提到的,您的雲功能不會為已刪除的teams
文檔觸發。
要刪除孤立player
文檔,您可以做的是每 X 分鍾/小時運行一次預定的雲功能。
以下 Cloud Function 使用CollectionGroup 查詢來獲取所有player
文檔並刪除它們。 請注意,您需要有一個用於查詢的 Firestore 索引。 還要注意我們如何使用Promise.all()
在所有異步工作完成后返回一個唯一的 Promise; 這是 正確管理 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)
});
現在,我們需要添加一個額外的業務邏輯。 僅當父team
文檔不存在時,才應刪除player
文檔。
以下代碼應該可以解決問題(未經測試):
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()
的數組)。 可能有一些優化代碼和減少循環次數的空間,但邏輯是存在的(如果我沒有做錯:-))。
Firebase 控制台通過這些斜體文件表明,這些文件實際上並不存在。 這些文檔不存在,要么是因為您沒有創建它們,要么是您明確刪除了它們。 所以這些文檔仍然顯示,因為它們下面有一個子集合。 所以基本上文檔的 ID 會以某種方式保留,如果您將來需要進行某些操作。
需要記住的一件事是,在 Cloud Firestore 中,文檔和子集合不像文件系統文件和目錄那樣工作。 所以總而言之,你不能刪除不存在的東西。 換句話說,由於該位置沒有物理文檔,因此您無法執行刪除操作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.