כלי נתונים
ששה כלים מכסים את כל העבודה מול הנתונים: שלושה קוראים (Get-Data, Count-Data, Aggregate-Data) ושלושה כותבים (Create-Data, Create-Many, Update-Data).
Get-Data
Section titled “Get-Data”שולף רשומות מטבלה.
| הפרמטר | טיפוס | חובה | המשמעות |
|---|---|---|---|
table |
String | ✔ | שם הטבלה (class name), למשל Accounts |
where |
Object | תנאי סינון. כל מפתח הוא שדה; מפתחות מרובים מתחברים ב‑AND | |
keys |
Array<String> | אילו שדות להחזיר (objectId, createdAt ו‑updatedAt חוזרים תמיד). ברירת מחדל — כל השדות |
|
order |
String | שדה למיון; קידומת - למיון יורד, למשל -createdAt |
|
limit |
Number | ברירת מחדל 5, מינימום 1, מקסימום 2000 — 0 או 2001 נדחים בוולידציה (Too small / Too big) |
|
skip |
Number | דילוג לצורך עימוד. ברירת מחדל 0 |
|
objectId |
String | מזהה רשומה בודדת. בדיוק 10 תווים (9 תווים נדחים בוולידציה). ראו למטה — מבטל את שאר הפרמטרים |
limit — המלכודת מספר 1
Section titled “limit — המלכודת מספר 1”{ "table": "Accounts", "where": { "IsAccount": false, "createdAt": { "$gt": { "__type": "Date", "iso": "2026-08-01" } } }, "keys": ["Name", "PhoneNumber", "LeadStatusId"], "order": "-createdAt", "limit": 200 }ברירת המחדל היא 5. לא 100, לא “הכול” — חמש. מודל שפה שמקבל חמש שורות ומדווח “מצאתי 5 לידים החודש” נשמע סמכותי לחלוטין, וטועה בסדר גודל.
הכלל: תמיד limit מפורש, גם כשנראה שהטבלה קטנה. אם צריך ספירה — לא שולפים, סופרים.
שימו לב שזה שונה מ‑REST, שם ברירת המחדל 100 ואין תקרה נאכפת על limit (על טבלה בת 2,101 שורות, limit=5000 החזיר את כל 2,101). מי שמעביר קוד בין השכבות מקבל תוצאה אחרת על אותה שאילתה. הכול במקום אחד: מגבלות ומכסות.
where — תחביר הסינון
Section titled “where — תחביר הסינון”מבוסס Parse. אופרטורים (כולם אומתו): $gt, $lt, $gte, $lte, $ne, $in, $nin, $exists, $regex.
{ "IsAccount": true, "City": { "$in": ["תל אביב", "רמת גן"] }, "Total": { "$gte": 10000 }, "ClosedAt": { "$exists": false }, "createdAt": { "$gte": { "__type": "Date", "iso": "2026-01-01T00:00:00.000Z" } }, "OwnerId": { "__type": "Pointer", "className": "_User", "objectId": "2b0QVKoigE" }}שתי נקודות שמפילות אנשים:
- סינון לפי Pointer דורש את האובייקט המלא —
{"__type":"Pointer","className":"…","objectId":"…"}. מחרוזת חשופה של ה‑objectId פשוט לא תואמת דבר, בשקט (נבדק:count: 0מולcount: 4עם האובייקט המלא). (בשכבת טפסי web2* זה הפוך — שם Pointer הוא מחרוזת. ראו סוגי נתונים.) - תאריך הוא אובייקט עטוף —
{"__type":"Date","iso":"…"}. מחרוזת תאריך חשופה מושווית כטקסט ומחזירה0תוצאות, בלי שגיאה.
שדות Pointer חוזרים בתשובה כאובייקט Pointer — {"__type":"Pointer","className":"SaleStatuses","objectId":"E9cYlAlooc"} — לא כמזהה בודד, אבל גם לא כרשומה המורחבת: אין include. כשצריך את השם של הסטטוס ולא את המזהה — Aggregate-Data עם מסלול Pointer, או שליפה נוספת.
objectId — פרמטר שאינו בקטלוג
Section titled “objectId — פרמטר שאינו בקטלוג”הסכימה החיה חושפת פרמטר objectId (בדיוק 10 תווים) לשליפת רשומה בודדת, והוא אינו מופיע בקטלוג הכלים הפנימי של המוצר. הסכימה גוברת.
{ "table": "Accounts", "objectId": "xK9mP2qRsT" }Count-Data
Section titled “Count-Data”סופר רשומות שעונות לתנאי — בלי להחזיר אותן.
| הפרמטר | טיפוס | חובה | המשמעות |
|---|---|---|---|
table |
String | ✔ | שם הטבלה |
where |
Object | אותו תחביר בדיוק כמו ב‑Get-Data |
{ "table": "Accounts", "where": { "IsAccount": false, "createdAt": { "$gte": { "__type": "Date", "iso": "2026-08-01T00:00:00.000Z" } } } }התשובה: {"count": 8}. בלי where — ספירת כל הטבלה.
זול משמעותית מ‑Get-Data, וחסין למלכודת ה‑limit: כשהשאלה היא “כמה”, Count-Data היא התשובה היחידה שאפשר לסמוך עליה. שאלה שנשמעת כמו “כמה לידים נכנסו החודש” ונענית בשליפה — נענית לא נכון.
Aggregate-Data
Section titled “Aggregate-Data”קיבוץ וצבירה בצד השרת: במקום למשוך 12,000 שורות ולסכם אותן בקוד, השרת מחזיר שורה לכל קבוצה.
| הפרמטר | טיפוס | חובה | המשמעות |
|---|---|---|---|
table |
String | ✔ | שם הטבלה |
group |
Object | ✔ | { "תווית": { "פונקציה": "שדה" } }. הסכימה מציינת “מאפיין אחד בלבד”, אבל השרת מקבל ומחשב כמה מאפיינים (ראו למטה) |
groupby |
String | Object | ✔ | לפי מה מקבצים — ראו למטה. חובה (בלי הפרמטר: groupby: Invalid input: expected nonoptional) |
where |
Object | סינון לפני הקיבוץ | |
order |
String | מיון; - לסדר יורד, למשל -total (לפי התווית המחושבת) |
|
limit |
Number | ברירת מחדל 0 = כל השורות, מקסימום 2000 (2001 נדחה בוולידציה) |
|
timeZone |
String | אזור זמן לחישוב חלקי תאריך, למשל Asia/Jerusalem (נבדק: hour של 10:00Z חוזר 12); ברירת מחדל — UTC של השרת |
התשובה: { "results": [ { "_id": <ערך-הקיבוץ>, "<תווית>": <ערך> }, … ] }. ב‑groupby מחרוזת _id הוא הערך עצמו (למשל שם הסטטוס); ב‑groupby אובייקט _id הוא אובייקט עם התוויות שלכם.
פונקציות הצבירה
Section titled “פונקציות הצבירה”| הפונקציה | מה היא עושה |
|---|---|
sum |
סכום ערכי שדה — {"total":{"sum":"Total"}} · או ספירה — {"count":{"sum":1}} |
avg |
ממוצע |
min / max |
הערך הנמוך / הגבוה בקבוצה |
first / last |
הערך הראשון / האחרון בקבוצה |
first ו‑last קיימים בסכימה החיה ואינם בקטלוג הפנימי. כל שש הפונקציות אומתו.
groupby — הסתירה שחשוב להכיר
Section titled “groupby — הסתירה שחשוב להכיר”הסכימה החיה מתירה שני מבנים:
// מחרוזת — שדה אחד{ "table": "Sales", "group": { "total": { "sum": "Total" } }, "groupby": "OwnerId._User.name", "order": "-total", "limit": 10 }// ⇒ {"results":[{"_id":"דנה לוי","total":3600}]}
// אובייקט — כמה שדות, ותוויות משלכם{ "table": "Sales", "group": { "total": { "sum": "Total" } }, "groupby": { "month": { "mm": "ClosingDate" }, "status": "SaleStatusId.SaleStatuses.Name" } }// ⇒ {"results":[{"_id":{"month":1,"status":"חדש"},"total":300}, …]}מסלול Pointer נכתב FieldName.TargetClassName.TargetFieldName — שם המחלקה באמצע, למשל SaleStatusId.SaleStatuses.Name או OwnerId._User.name. זה בדיוק מה ש‑אגרגציית REST הגולמית לא יודעת לעשות, וזו הסיבה המרכזית להעדיף את הכלי הזה כשצריך שמות ולא מזהים.
חלקי תאריך שאפשר לקבץ לפיהם (כולם אומתו): hour, dow (יום בשבוע, 1 = ראשון), q (רבעון), q/yy (⇒ {"yy":2026,"q":1}), mm (חודש), mm/yy (⇒ {"yy":2026,"mm":3}), yy. חלק תאריך נכתב תמיד בצורת האובייקט: { "label": { "mm": "ClosingDate" } }.
דוגמה מלאה — הכנסות לפי בעלים
Section titled “דוגמה מלאה — הכנסות לפי בעלים”{ "table": "Sales", "where": { "SaleStatusId": { "__type": "Pointer", "className": "SaleStatuses", "objectId": "zrP1MSVBoq" }, "ClosingDate": { "$gte": { "__type": "Date", "iso": "2026-01-01T00:00:00.000Z" } } }, "group": { "total": { "sum": "Total" } }, "groupby": "OwnerId._User.name", "order": "-total", "limit": 10 }Create-Data
Section titled “Create-Data”יוצר רשומה אחת.
| הפרמטר | טיפוס | חובה | המשמעות |
|---|---|---|---|
table |
String | ✔ | שם הטבלה |
data |
Object | ✔ | מפת שדה → ערך |
{ "table": "Tasks", "data": { "Name": "לחזור ללקוח", "DueDate": { "__type": "Date", "iso": "2026-09-01T09:00:00.000Z" }, "AccountId": { "__type": "Pointer", "className": "Accounts", "objectId": "xK9mP2qRsT" }, "OwnerId": { "__type": "Pointer", "className": "_User", "objectId": "2b0QVKoigE" } } }התשובה: { "objectId": "LyRGHAc68z", "createdAt": "2026-08-23T11:16:22.956Z" }.
אין ל‑Create-Data דגלי דילוג. טריגרים ירוצו (נבדק: טריגר create על הטבלה יצר את רשומת הבת שלו), וכך גם רישום ציר הזמן — אם לטבלה יש הגדרות ציר זמן; השורה ב‑_Timeline נרשמת עם user.objectId === "Master".
Create-Many
Section titled “Create-Many”יוצר רשומות בכמות. זהו כלי העבודה של כל טעינת נתונים.
| הפרמטר | טיפוס | חובה | המשמעות |
|---|---|---|---|
table |
String | ✔ | שם הטבלה |
data |
Array<Object> | ✔ | מערך של רשומות, כל אחת כמו ב‑Create-Data |
skipTriggers |
Boolean | מדלג על כל טריגרי היצירה של הטבלה (אומת: עם הדגל לא נוצרה רשומת הבת של הטריגר; בלעדיו — כן) | |
skipTimeline |
Boolean | מונע רישום ל‑_Timeline (אומת: 0 שורות מול 1 בלעדיו) |
{ "table": "Accounts", "skipTriggers": true, "data": [ { "Name": "לקוח א'", "PhoneNumber": "0501234567", "IsAccount": false }, { "Name": "לקוח ב'", "PhoneNumber": "0507654321", "IsAccount": false } ] }התשובה היא מערך בסדר הקלט, פריט לכל רשומה:
[ { "success": { "objectId": "ivgBTJUiUZ", "createdAt": "2026-08-23T11:16:14.069Z" } }, { "success": { "objectId": "TqbPMxcyAG", "createdAt": "2026-08-23T11:16:14.069Z" } } ]זו הדרך לקשר בין שורות המקור לרשומות שנוצרו כשטוענים שתי טבלאות בזו אחר זו (ראו מתכונים). נבדק: 8 רשומות חזרו בדיוק בסדר השליחה.
skipTimeline מקטין את יכולת המעקב. השתמשו בו רק כשאתם יודעים למה — יומנים וראיות מסביר מה מאבדים.
גודל אצווה מומלץ: עד ~50 רשומות לקריאה. אין מגבלה מוצהרת בסכימה, ואצוות של 60 ו‑120 רשומות עברו בבדיקה, אבל תשובה של מאות מזהים מכבידה על הקשר המודל. לסטים גדולים — לולאה של אצוות. (ל‑batch של REST מומלצות עד 50 פעולות לקריאה, אבל זו המלצה ולא אכיפה: אצווה של 1,000 פעולות עברה בבדיקה. דגלי דילוג אין לו בכלל.)
Update-Data
Section titled “Update-Data”מעדכן רשומה אחת קיימת.
| הפרמטר | טיפוס | חובה | המשמעות |
|---|---|---|---|
table |
String | ✔ | שם הטבלה |
objectId |
String | ✔ | מזהה הרשומה. בדיוק 10 תווים |
data |
Object | ✔ | השדות לעדכון בלבד — שדה שלא נשלח לא נוגעים בו (אומת) |
{ "table": "Sales", "objectId": "V0sVNyS45K", "data": { "SaleStatusId": { "__type": "Pointer", "className": "SaleStatuses", "objectId": "zrP1MSVBoq" }, "Total": { "__op": "Increment", "amount": 500 }, "ClosingDate": { "__type": "Date", "iso": "2026-09-30T00:00:00.000Z" } } }התשובה: objectId, updatedAt, והשדות שחושבו בשרת (למשל "Total": 510 אחרי Increment). מזהה שאינו קיים ⇒ Error: Object not found.
{"__op": "Increment", "amount": n} מגדיל שדה מספרי בצד השרת — הדרך הנכונה למונים, כי היא לא מכניסה מרוץ בין קריאה לכתיבה. ערך שלילי מקטין.
אין כלי לעדכון בכמות. עדכון גורף הוא לולאה של Update-Data, או batch ב‑REST.
שלוש המלכודות היקרות
Section titled “שלוש המלכודות היקרות”| המלכודת | מה קורה | ההגנה |
|---|---|---|
limit ברירת מחדל 5 |
תשובה קטומה שנראית שלמה; אין שגיאה | limit מפורש תמיד; Count-Data כששואלים “כמה” |
skipTriggers / skipTimeline רק ב‑Master Key |
בחיבור משתמש הדגל מתעלם בשקט; סופת טריגרים | לוודא את שיטת האימות לפני טעינה; Get-Triggers מראש |
| אין מחיקה | תכנון שמניח “ננקה אחר כך” נתקע | לתכנן סימון ביטול, לא מחיקה; ניקוי אמיתי — ממשק או REST |
- מתכונים — משימות נפוצות דרך MCP
- אינדקס הכלים המלא
- סוכן במצב קריאה בלבד
- כלי טריגרים ואוטומציות — מה בדיוק ירוץ כשאתם כותבים
- שאילתות ב‑REST · אגרגציות ב‑REST · סוגי נתונים