כלי נתונים
ששה כלים מכסים את כל העבודה מול הנתונים: שלושה קוראים (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במקום התוצאה האמיתית. בשכבת טפסי 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" } } ]זו הדרך לקשר בין שורות המקור לרשומות שנוצרו כשטוענים שתי טבלאות בזו אחר זו (ראו מתכונים). הסדר נשמר בדיוק כסדר השליחה.
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 · סוגי נתונים