מחיקת נתונים באמצעות פונקציה של Cloud Functions שניתנת לקריאה
קל לארגן דפים בעזרת אוספים
אפשר לשמור ולסווג תוכן על סמך ההעדפות שלך.
בדף הזה מוסבר איך להשתמש ב-Cloud Function שאפשר להפעיל כדי למחוק נתונים. אחרי שמפעילים את הפונקציה הזו, אפשר לקרוא לה ישירות מאפליקציית מובייל או מאתר כדי למחוק מסמכים ואוספים באופן רקורסיבי. לדוגמה, אפשר להשתמש בפתרון הזה כדי לתת למשתמשים נבחרים את האפשרות למחוק אוספים שלמים.
דרכים נוספות למחוק אוספים מפורטות במאמר מחיקת נתונים.
פתרון: מחיקת נתונים באמצעות Cloud Function שאפשר להפעיל
יכול להיות שיהיה קשה להטמיע מחיקה של אוספים שלמים באפליקציה לנייד עם משאבים מוגבלים, מהסיבות הבאות:
אין פעולה שמוחקת אוסף באופן אטומי.
כשמוחקים מסמך, המסמכים באוספי המשנה שלו לא נמחקים.
אם במסמכים שלכם יש אוספי משנה דינמיים, יכול להיות שיהיה לכם קשה לדעת אילו נתונים למחוק בנתיב מסוים.
כדי למחוק אוסף של יותר מ-500 מסמכים, צריך לבצע כמה פעולות כתיבה באצווה או מאות מחיקות בודדות.
בהרבה אפליקציות, לא מתאים לתת למשתמשי קצה הרשאה למחוק אוספים שלמים.
למזלכם, אתם יכולים לכתוב פונקציית Cloud שאפשר להפעיל כדי למחוק בבטחה וביעילות קולקציות שלמות או עץ של קולקציות. הפונקציה הבאה של Cloud Functions היא פונקציה שאפשר להפעיל, כלומר אפשר להפעיל אותה ישירות מהאפליקציה לנייד או מהאתר, כמו שמפעילים פונקציה מקומית.
כדי לפרוס את הפונקציה ולנסות הדגמה, אפשר לעיין בקוד לדוגמה.
Cloud Function
הפונקציה של Cloud Functions שמופיעה בהמשך מוחקת אוסף ואת כל צאצאיו.
במקום להטמיע לוגיקה משלכם למחיקה רקורסיבית של Cloud Function, אתם יכולים להשתמש בפקודה firestore:delete בממשק שורת הפקודה (CLI) של Firebase. אתם יכולים לייבא כל פונקציה של Firebase CLI לאפליקציית Node.js באמצעות חבילת firebase-tools.
ה-Firebase CLI משתמש ב-Cloud Firestore REST API כדי למצוא את כל המסמכים בנתיב שצוין ולמחוק אותם בנפרד.
ההטמעה הזו לא דורשת ידע בהיררכיית הנתונים הספציפית של האפליקציה, והיא אפילו תמצא ותמחק מסמכים 'יתומים' שכבר אין להם מסמך אב.
Node.js
/** * Initiate a recursive delete of documents at a given path. * * The calling user must be authenticated and have the custom "admin" attribute * set to true on the auth token. * * 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.recursiveDelete=functions.runWith({timeoutSeconds:540,memory:'2GB'}).https.onCall(async(data,context)=>{// Only allow admin users to execute this function.if(!(context.auth && context.auth.token && context.auth.token.admin)){thrownewfunctions.https.HttpsError('permission-denied','Must be an administrative user to initiate delete.');}constpath=data.path;console.log(`User ${context.auth.uid} has requested to delete path ${path}`);// Run a recursive delete on the given document or collection path.// The 'token' must be set in the functions config, and can be generated// at the command line by running 'firebase login:ci'.awaitfirebase_tools.firestore.delete(path,{project:process.env.GCLOUD_PROJECT,recursive:true,force:true,token:functions.config().fb.token});return{path:path};});
כדי לקרוא לפונקציה, צריך לקבל הפניה לפונקציה מ-Firebase SDK ולהעביר את הפרמטרים הנדרשים:
אינטרנט
/** * Call the 'recursiveDelete' callable function with a path to initiate * a server-side delete. */functiondeleteAtPath(path){vardeleteFn=firebase.functions().httpsCallable('recursiveDelete');deleteFn({path:path}).then(function(result){logMessage('Delete success: '+JSON.stringify(result));}).catch(function(err){logMessage('Delete failed, see console,');console.warn(err);});}
הערה: המוצר הזה לא זמין ב-watchOS וביעדים של קליפים של אפליקציות.
// Snippet not yet written
Objective-C
הערה: המוצר הזה לא זמין ב-watchOS וביעדים של קליפים של אפליקציות.
// Snippet not yet written
Kotlin
/** * Call the 'recursiveDelete' callable function with a path to initiate * a server-side delete. */fundeleteAtPath(path:String){valdeleteFn=Firebase.functions.getHttpsCallable("recursiveDelete")deleteFn.call(hashMapOf("path"topath)).addOnSuccessListener{// Delete Success// ...}.addOnFailureListener{// Delete Failed// ...}}
/** * Call the 'recursiveDelete' callable function with a path to initiate * a server-side delete. */publicvoiddeleteAtPath(Stringpath){Map<String,Object>data=newHashMap<>();data.put("path",path);HttpsCallableReferencedeleteFn=FirebaseFunctions.getInstance().getHttpsCallable("recursiveDelete");deleteFn.call(data).addOnSuccessListener(newOnSuccessListener<HttpsCallableResult>(){@OverridepublicvoidonSuccess(HttpsCallableResulthttpsCallableResult){// Delete Success// ...}}).addOnFailureListener(newOnFailureListener(){@OverridepublicvoidonFailure(@NonNullExceptione){// Delete failed// ...}});}
באמצעות ה-SDK של הלקוח לפונקציות בענן שאפשר להפעיל, מצב האימות של המשתמש והפרמטר path מועברים בצורה חלקה לפונקציה המרוחקת.
כשהפונקציה מסתיימת, הלקוח מקבל קריאה חוזרת עם התוצאה או עם חריגה. במסמכי התיעוד מוסבר איך להתקשר לפונקציית Cloud מ-Android, מ-Apple או מפלטפורמה אחרת.
מגבלות
הפתרון שמוצג למעלה מדגים איך למחוק אוספים מפונקציה שאפשר לקרוא לה, אבל חשוב להיות מודעים למגבלות הבאות:
עקביות – הקוד שלמעלה מוחק מסמכים אחד בכל פעם. אם תבצעו שאילתה בזמן פעולת מחיקה, יכול להיות שהתוצאות ישקפו מצב של השלמה חלקית, שבו רק חלק מהמסמכים שהוגדרו למחיקה נמחקו.
בנוסף, אין ערובה לכך שפעולות המחיקה יצליחו או ייכשלו באופן אחיד, ולכן צריך להיות מוכנים לטפל במקרים של מחיקה חלקית.
פסק זמן (timeout) – הפונקציה שלמעלה מוגדרת לפעול למשך 540 שניות לכל היותר לפני שיופעל פסק זמן. קוד המחיקה יכול למחוק 4,000 מסמכים בשנייה במקרה הטוב. אם אתם צריכים למחוק יותר מ-2,000,000 מסמכים, כדאי להריץ את הפעולה בשרת שלכם כדי שלא יתרחש פסק זמן. דוגמה למחיקת אוסף מהשרת שלכם מופיעה במאמר בנושא מחיקת אוספים.
מחיקה של מספר גדול של מסמכים עלולה לגרום לטעינה איטית של כלי הצגת הנתונים במסוף Google Cloud או להחזרת שגיאת זמן קצוב לתפוגה.
[[["התוכן קל להבנה","easyToUnderstand","thumb-up"],["התוכן עזר לי לפתור בעיה","solvedMyProblem","thumb-up"],["סיבה אחרת","otherUp","thumb-up"]],[["חסרים לי מידע או פרטים","missingTheInformationINeed","thumb-down"],["התוכן מורכב מדי או עם יותר מדי שלבים","tooComplicatedTooManySteps","thumb-down"],["התוכן לא עדכני","outOfDate","thumb-down"],["בעיה בתרגום","translationIssue","thumb-down"],["בעיה בדוגמאות/בקוד","samplesCodeIssue","thumb-down"],["סיבה אחרת","otherDown","thumb-down"]],["עדכון אחרון: 2025-09-05 (שעון UTC)."],[],[],null,["\u003cbr /\u003e\n\nThe page describes how to use a callable Cloud Function\nto delete data. Once you deploy this function,\nyou can call it directly from your mobile app or website to\nrecursively delete documents and collections. For example, you can use this\nsolution to give select users the ability to delete entire collections.\n\nFor other ways to delete collections, see [Delete data](../manage-data/delete-data#collections).\n\nSolution: Delete data with a callable Cloud Function\n\nDeleting entire collections from a resource-limited mobile app can be difficult\nto implement for the following reasons:\n\n- There is no operation that atomically deletes a collection.\n- Deleting a document does not delete the documents in its subcollections.\n- If your documents have dynamic subcollections, it can be hard to know what data to delete for a given path.\n- Deleting a collection of more than 500 documents requires multiple batched write operations or hundreds of single deletes.\n- In many apps, it isn't appropriate to give end-users permission to delete entire collections.\n\nFortunately, you can write a [callable Cloud Function](https://firebase.google.com/docs/functions/callable)\nto run safe and performant deletes of entire collections or collection trees. The Cloud Function below implements a [callable function](https://firebase.google.com/docs/functions/callable)\nwhich means it can be called directly from your mobile app or website as you\nwould for a local function.\n\nTo deploy the function and try a demo, see the [sample code](https://github.com/firebase/snippets-node/tree/master/firestore/solution-deletes).\n\nCloud Function\n\nThe Cloud Function below deletes a collection and all of its descendants.\n\nInstead of implementing your own recursive delete logic for your Cloud Function,\nyou can take advantage of the `firestore:delete` command in the\nFirebase Command Line Interface (CLI). You can import any function of the\nFirebase CLI into your Node.js application using the `firebase-tools` package.\n| **Note:** Deleting data with the Firebase CLI incurs read and delete costs. For more information, see [Pricing](https://firebase.google.com/docs/firestore/pricing).\n\nThe Firebase CLI uses the Cloud Firestore REST API\nto find all documents under the specified path and delete them individually.\nThis implementation requires no knowledge of your app's specific data hierarchy\nand will even find and delete \"orphaned\" documents that no longer have a\nparent. \n\nNode.js \n\n```javascript\n/**\n * Initiate a recursive delete of documents at a given path.\n * \n * The calling user must be authenticated and have the custom \"admin\" attribute\n * set to true on the auth token.\n * \n * This delete is NOT an atomic operation and it's possible\n * that it may fail after only deleting some documents.\n * \n * @param {string} data.path the document or collection path to delete.\n */\nexports.recursiveDelete = functions\n .runWith({\n timeoutSeconds: 540,\n memory: '2GB'\n })\n .https.onCall(async (data, context) =\u003e {\n // Only allow admin users to execute this function.\n if (!(context.auth && context.auth.token && context.auth.token.admin)) {\n throw new functions.https.HttpsError(\n 'permission-denied',\n 'Must be an administrative user to initiate delete.'\n );\n }\n\n const path = data.path;\n console.log(\n `User ${context.auth.uid} has requested to delete path ${path}`\n );\n\n // Run a recursive delete on the given document or collection path.\n // The 'token' must be set in the functions config, and can be generated\n // at the command line by running 'firebase login:ci'.\n await firebase_tools.firestore\n .delete(path, {\n project: process.env.GCLOUD_PROJECT,\n recursive: true,\n force: true,\n token: functions.config().fb.token\n });\n\n return {\n path: path \n };\n });https://github.com/firebase/snippets-node/blob/f1869eeb97c2bbb713aff3deb5a67666da7bcb6b/firestore/solution-deletes/functions/index.js#L29-L73\n```\n\nClient Invocation\n\nTo call the function, get a reference to the function from the Firebase SDK\nand pass the required parameters: \n\nWeb \n\n```javascript\n/**\n * Call the 'recursiveDelete' callable function with a path to initiate\n * a server-side delete.\n */\nfunction deleteAtPath(path) {\n var deleteFn = firebase.functions().httpsCallable('recursiveDelete');\n deleteFn({ path: path })\n .then(function(result) {\n logMessage('Delete success: ' + JSON.stringify(result));\n })\n .catch(function(err) {\n logMessage('Delete failed, see console,');\n console.warn(err);\n });\n}https://github.com/firebase/snippets-node/blob/f1869eeb97c2bbb713aff3deb5a67666da7bcb6b/firestore/solution-deletes/public/index.js#L4-L18\n```\n\nSwift \n**Note:** This product is not available on watchOS and App Clip targets. \n\n```swift\n // Snippet not yet written\n \n```\n\nObjective-C \n**Note:** This product is not available on watchOS and App Clip targets. \n\n```objective-c\n // Snippet not yet written\n \n```\n\nKotlin \n\n```kotlin\n/**\n * Call the 'recursiveDelete' callable function with a path to initiate\n * a server-side delete.\n */\nfun deleteAtPath(path: String) {\n val deleteFn = Firebase.functions.getHttpsCallable(\"recursiveDelete\")\n deleteFn.call(hashMapOf(\"path\" to path))\n .addOnSuccessListener {\n // Delete Success\n // ...\n }\n .addOnFailureListener {\n // Delete Failed\n // ...\n }\n}https://github.com/firebase/snippets-android/blob/b694d4dbd411d31be39655f47691c3e9f3529b03/firestore/app/src/main/java/com/google/example/firestore/kotlin/SolutionDeletes.kt#L9-L24\n```\n\nJava \n\n```java\n/**\n * Call the 'recursiveDelete' callable function with a path to initiate\n * a server-side delete.\n */\npublic void deleteAtPath(String path) {\n Map\u003cString, Object\u003e data = new HashMap\u003c\u003e();\n data.put(\"path\", path);\n\n HttpsCallableReference deleteFn =\n FirebaseFunctions.getInstance().getHttpsCallable(\"recursiveDelete\");\n deleteFn.call(data)\n .addOnSuccessListener(new OnSuccessListener\u003cHttpsCallableResult\u003e() {\n @Override\n public void onSuccess(HttpsCallableResult httpsCallableResult) {\n // Delete Success\n // ...\n }\n })\n .addOnFailureListener(new OnFailureListener() {\n @Override\n public void onFailure(@NonNull Exception e) {\n // Delete failed\n // ...\n }\n });\n}https://github.com/firebase/snippets-android/blob/b694d4dbd411d31be39655f47691c3e9f3529b03/firestore/app/src/main/java/com/google/example/firestore/SolutionDeletes.java#L17-L42\n```\n\nBy using the client SDK for callable cloud functions, the users's authentication\nstate and the `path` parameter are seamlessly passed to the remote function.\nWhen the function completes, the client will receive a callback with the\nresult or an exception. To learn about how to call a cloud function from\nAndroid, Apple, or another platform, read [the documentation](https://firebase.google.com/docs/functions/callable#call_the_function).\n| **Warning:** Callable functions are not secure by default! Make sure that your callable functions check the user's authorization before performing any sensitive actions like writing or deleting documents.\n\nLimitations\n\nThe solution shown above demonstrates deleting collections from a callable\nfunction, but you should be aware of the following limitations:\n\n- **Consistency** - the code above deletes documents one at a time. If you query while there is an ongoing delete operation, your results may reflect a partially complete state where only some targeted documents are deleted. There is also no guarantee that the delete operations will succeed or fail uniformly, so be prepared to handle cases of partial deletion.\n- **Timeouts** - the function above is configured to run for a maximum of 540 seconds before timing out. The deletion code can delete 4000 documents per second in the best case. If you need to delete more than 2,000,000 documents, you should consider running the operation on your own server so that it does not time out. For an example of how to delete a collection from your own server, see [Delete collections](../manage-data/delete-data#collections).\n- Deleting a large number of documents might cause the data viewer in the Google Cloud console to load slowly or to return a timeout error."]]