שינוי נתונים באמצעות פעולות ב-Pipeline
משתמשים בשלבים של שפת הטיפול בנתונים (DML) ב-update(...) וב-delete(...) כדי ליצור פייפליינים שיכולים לשלוח שאילתות למסמכים ואז למחוק או לשנות נתונים.
דרישות לגבי המהדורה
כדי לבצע את הפעולות שמתוארות בדף הזה, צריך את מהדורת Firestore Enterprise.
לפני שמתחילים
אתם צריכים לדעת איך לשלוח שאילתות למסד נתונים באמצעות פעולות Pipeline.
עדכון מסמכים
משתמשים בשלב update(...) ב-DML כדי ליצור פייפליינים שיכולים לשלוח שאילתות למסמכים ואז להוסיף או לשנות נתונים.
כל שלבי ה-DML חייבים להופיע בסוף צינור עיבוד הנתונים.
המסמכים שמגיעים לשלב הזה חייבים לכלול את השדה __name__ כדי לזהות אילו מסמכים צריך לעדכן. הפעולה תיכשל אם אחד מהמסמכים שאתם מנסים לעדכן לא קיים.
לדוגמה, הפעולה הבאה ממלאת באופן רטרואקטיבי שינוי במודל הנתונים בכל המסמכים בקבוצת אוספים. הצינור מוסיף שדה preferences.color לכל המסמכים בקבוצת האוספים users שחסר בהם השדה הזה.
Node.js
const snapshot = await db.pipeline() .collectionGroup("users") .where(not(exists(field("preferences.color")))) .addFields(constant(null).as("preferences.color")) .removeFields("color") .update() .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Constant, Field, Not snapshot = ( client.pipeline() .collection_group("users") .where(Not(Field.of("preferences.color").exists())) .add_fields(Constant.of(None).as_("preferences.color")) .remove_fields("color") .update() .execute() )
Java
Pipeline.Snapshot snapshot = firestore.pipeline() .collectionGroup("users") .where(not(exists(field("preferences.color")))) .addFields(constant((String) null).as("preferences.color")) .removeFields("color") .update() .execute().get();
המשך
snapshot := client.Pipeline(). CollectionGroup("users"). Where(firestore.Not(firestore.FieldExists(firestore.FieldOf("preferences.color")))). AddFields(firestore.Selectables( firestore.ConstantOfNull().As("preferences.color"), )). RemoveFields(firestore.Fields("color")). Update(). Execute(ctx)
מחיקת המסמכים
משתמשים בשלב delete(...) ב-DML כדי ליצור פייפליינים שיכולים לשלוח שאילתות למסמכים ואז למחוק נתונים.
כדי למנוע מחיקות בכמות גדולה בטעות, צינורות עיבוד נתונים שמסתיימים ב-delete(...) צריכים לכלול לפחות שלב where(...) אחד.
כל שלבי ה-DML חייבים להופיע בסוף צינור עיבוד הנתונים.
לדוגמה, צינור עיבוד הנתונים הבא מוחק את כל המסמכים של users שבהם address.users מוגדר כ-USA ו-__create_time__ קטן מ-10 ימים:
Node.js
const pipeline = db.pipeline() .collectionGroup("users") .where(field("address.country").equal("USA")) .where(field("__create_time__").timestampAdd("day", 10).lessThan(currentTimestamp())) .delete(); await pipeline.execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import CurrentTimestamp, Field snapshot = ( client.pipeline() .collection_group("users") .where(Field.of("address.country").equal("USA")) .where( Field.of("__create_time__") .timestamp_add("day", 10) .less_than(CurrentTimestamp()) ) .delete() .execute() )
Java
Pipeline.Snapshot deleteResults = firestore.pipeline() .collectionGroup("users") .where(field("address.country").equal("USA")) .where(field("__create_time__").add(constant(10)).lessThan(currentTimestamp())) .delete() .execute().get();
המשך
snapshot := client.Pipeline(). CollectionGroup("users"). Where(firestore.FieldOf("address.country").Equal("USA")). Where(firestore.FieldOf("__create_time__").Add(firestore.ConstantOf(10)).LessThan(firestore.CurrentTimestamp())). Delete(). Execute(ctx)
מצבי הרצה ועקביות
אפשר להריץ שלבי DML בתוך טרנזקציה מפורשת או מחוץ לטרנזקציה:
ביצוע טרנזקציות
DML טרנזקציונלי מספק עקביות אטומית, הכל או כלום, בין מסמכים ותומך בקבוצה המלאה של שלבי השאילתות בצינור עיבוד הנתונים. לכן, הוא אידיאלי לעומסי עבודה שדורשים עקביות קפדנית – שבהם עדכונים חלקיים לא מקובלים – או שמסתמכים על שלבי שאילתות מורכבים, בתנאי שהשינויים מתאימים למגבלות הגודל של הטרנזקציה.
כשמריצים צינור עיבוד נתונים של DML בתוך טרנזקציה מפורשת (באמצעות runTransaction / transaction.execute(pipeline) או האפשרות atomic: true), מתקבלת ההתנהגות הבאה:
- כל השינויים מתבצעים יחד או מתבטלים לחלוטין במקרה של כשל.
- כל שלבי השאילתות בצינור עיבוד הנתונים נתמכים לפני שלב DML (כולל שאילתות משנה של
where,add_fields,union,find_nearestו-aggregate). - בטרנזקציה, כל פעולות הקריאה חייבות להתבצע לפני פעולות הכתיבה. צינור עיבוד נתונים של DML מבצע כתיבות, ולכן אי אפשר לבצע קריאות אחרי הרצה של צינור עיבוד נתונים של DML באותה טרנזקציה. לדוגמה, אי אפשר לקרוא לצינור עיבוד נתונים של DML כמה פעמים בעסקה אחת, ואי אפשר לקרוא מסמכים אחרי שמפעילים צינור עיבוד נתונים של DML. ניסיון לבצע קריאה אחרי הרצה של צינור עיבוד נתונים של DML נכשל עם השגיאה
FAILED_PRECONDITION:Cannot have reads after the first write in a Firestore transaction. - הפעולה כפופה למגבלות העסקאות של מהדורת Firestore Enterprise.
ביצוע ללא טרנזקציה
DML ללא טרנזקציות מיועד לשינויים בכמות גדולה של מסמכים, בלי להיתקל במגבלות על גודל הטרנזקציות. הנעילה מתבצעת ברמת המסמך ולא בכל הפעולה, כך שאפשר לבצע פעולות אחרות במקביל בזמן שמעדכנים מסמכים בקנה מידה נרחב.
כששלבי DML פועלים מחוץ לעסקה מפורשת:
- עדכונים נפרדים והצלחה חלקית: כל מסמך מתעדכן בנפרד, והפעולות לא אטומיות בין המסמכים. הצינור נעצר בשגיאה הראשונה, ומסמכים ששונו קודם לכן נשארים כתובים במסד הנתונים, מה שמאפשר הצלחה חלקית.
- תמיכה בשלבים:
- שלבים מתקדמים ושלבים עם כמה שאילתות (כמו
aggregate(...),distinct(...),unnest(...),find_nearest(...),union(...), איחודים ושאילתות משנה) לא נתמכים לפני DML מחוץ לטרנזקציה. אם תהליך המכירה שלכם כולל את השלבים האלה, השתמשו בעסקה.
- שלבים מתקדמים ושלבים עם כמה שאילתות (כמו
- מגבלת 20 החיפושים של כללי האבטחה: כל קבוצת מסמכים מופעלת בטרנזקציה משלה, וכללי האבטחה מוערכים מחדש. אם כללי האבטחה משתמשים בחיפושים של
get()אוexists(), כל אצווה מבצעת חיפוש, מגיעה למגבלה של 20 חיפושים לכל בקשה אחרי כתיבה של כ-200 מסמכים ונכשלת עםPERMISSION_DENIED. כדי להימנע מהמגבלה הזו, השתמשו בהצהרות מותאמות אישית במקום בחיפושים שלget()אוexists().
מגבלות
שימו לב למגבלות הבאות בשלבי DML:
- שלבי DML חייבים להיות השלב האחרון בהגדרה של צינור עיבוד נתונים לפני הקריאה ל-
.execute(). - כשמריצים את הפעולה מחוץ לטרנזקציה, כל מסמך מתעדכן בנפרד, כך שחלק מהמסמכים יכולים להתעדכן וחלק לא.
- פעולות DML שאינן טרנזקציות, שכפופות לכללי אבטחה עם חיפושים של
get()אוexists(), מוגבלות לכ-200 מסמכים בגלל מגבלת 20 החיפושים. - פעולות DML טרנזקציונליות מוגבלות על ידי מגבלות העסקאות של מהדורת Firestore Enterprise. בטרנזקציות של Firestore אי אפשר לבצע קריאות אחרי הכתיבה הראשונה, ולכן אי אפשר לקרוא לצינור עיבוד נתונים של DML כמה פעמים בטרנזקציה אחת, ואי אפשר לקרוא מסמכים אחרי הפעלת צינור עיבוד נתונים של DML.
ניסיון לבצע קריאה אחרי כתיבת DML נכשל עם השגיאה
FAILED_PRECONDITION:Cannot have reads after the first write in a Firestore transaction. - אם השלב שלפני שלב ה-DML יוצר כמה מסמכים עם אותו
__name__או מחשב את אותו מזהה מסמך יעד, כל שינוי מעובד ברצף:- ב-
upsert(...)וב-update(...): אם יש כמה מוטציות שמטרגטות את אותו מסמך, המוטציה האחרונה שעובדה קובעת את המצב הסופי של המסמך. - ב-
delete(...): הניסיון הראשון מוחק את המסמך, וניסיונות נוספים לאותו מסמך לא מבצעים פעולה. - ב-
insert(...): בניסיון הראשון נוצר המסמך, ובניסיונות הבאים לטרגט את אותו מזהה מסמך מופיעה השגיאהALREADY_EXISTS.
- ב-