אגרגציות ב‑REST
שורה אחת לכל קבוצה, במקום למשוך 12,000 שורות ולסכום אותן בקוד.
הפרמטרים
Section titled “הפרמטרים”| פרמטר | טיפוס | משמעות |
|---|---|---|
group |
JSON | חובה. אופרטור יחיד בצורה {"<פונקציה>":"<שדה>"}. בלעדיו: {"code":102,"error":"missing parameter for query: group"} |
groupby |
מחרוזת | לפי מה מקבצים — שדה רגיל, Boolean, Date, Pointer, או דוט‑נוטציה דרך Pointer. בלעדיו מתקבלת שורה אחת לכל הטבלה ({"_id":null,"value":…}) — סכום כולל |
where |
JSON | הסינון — אותה שפה בדיוק כמו ב‑שאילתות |
order |
מחרוזת | מיון התוצאות. -value = יורד |
limit |
מספר | הגבלת מספר הקבוצות המוחזרות |
כמו ב‑שאילתות, כל ערך JSON חייב לעבור קידוד URL.
הפונקציות
Section titled “הפונקציות”| הפונקציה | הצורה |
|---|---|
| סכום | group={"sum":"Total"} |
| ספירה | group={"sum":1} |
| ממוצע | group={"avg":"Total"} |
| מינימום / מקסימום | group={"min":"Total"} · group={"max":"Total"} |
| ערך ראשון / אחרון | group={"first":"Total"} · group={"last":"Total"} |
| כל הערכים כמערך | group={"push":"Total"} |
| הערכים הייחודיים כמערך | group={"addToSet":"Total"} |
count, stdDev ו‑stdDevPop אינם אופרטורים מוכרים — לספירה השתמשו ב‑{"sum":1}.
אופרטור אחד בכל בקשה. שני מפתחות ב‑group מוחזרים עם the group must specify exactly one operator, ושם פונקציה שאינו מוכר עם the group aggregate funciton name <X> must be a valid operator name (שגיאת הכתיב funciton היא במחרוזת שהשרת מחזיר).
אין $ לפני שם הפונקציה ולא לפני שם השדה: {"$sum":"$Total"} נדחה באותה הודעה. גם הצורה עם תווית של MCP ({"total":{"sum":"Total"}}) נדחית כאן.
שגיאות שדה, כולן 400 עם code 102: שדה שאינו מספרי ב‑sum/avg מחזיר the type of the group aggregate field (<Field>) must be "Number"; שדה לא קיים ב‑groupby מחזיר Invalid parameter for groupby: <Field>; group שאינו JSON מחזיר group must be valid json. טבלה שאינה קיימת מחזירה {"code":119,"error":"This user is not allowed to access non-existent class: <Table>"}. ההתנהגות מול /classes/ תלויה באישור: עם Master Key שליפה מ‑/classes/<Table> על טבלה לא קיימת מחזירה 200 ומערך ריק, עם X-Parse-API-Key גם /classes/ מחזיר את אותה 400 עם code 119.
סכום עסקאות לפי שלב
Section titled “סכום עסקאות לפי שלב”curl -sS -G "https://api.mbapps.co.il/parse/classes-aggregate/Sales" \ -H "X-Parse-Application-Id: $APP_ID" \ -H "X-Parse-API-Key: $API_KEY" \ --data-urlencode 'group={"sum":"Total"}' \ --data-urlencode 'groupby=SaleStatusId'const APP_ID = process.env.APP_ID, API_KEY = process.env.API_KEY;
const params = new URLSearchParams({ group: '{"sum":"Total"}', groupby: 'SaleStatusId',});
const res = await fetch(`https://api.mbapps.co.il/parse/classes-aggregate/Sales?${params}`, { headers: { 'X-Parse-Application-Id': APP_ID, 'X-Parse-API-Key': API_KEY, },});const data = await res.json();import os, requests
APP_ID = os.environ["APP_ID"]API_KEY = os.environ["API_KEY"]
res = requests.get( "https://api.mbapps.co.il/parse/classes-aggregate/Sales", headers={ "X-Parse-Application-Id": APP_ID, "X-Parse-API-Key": API_KEY, }, params={ "group": '{"sum":"Total"}', "groupby": "SaleStatusId", },)data = res.json()<?php$appId = getenv('APP_ID');$apiKey = getenv('API_KEY');
$query = http_build_query([ 'group' => '{"sum":"Total"}', 'groupby' => 'SaleStatusId',]);
$ch = curl_init();curl_setopt_array($ch, [ CURLOPT_URL => "https://api.mbapps.co.il/parse/classes-aggregate/Sales?$query", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "X-Parse-Application-Id: $appId", "X-Parse-API-Key: $apiKey", ],]);$response = curl_exec($ch);curl_close($ch);$data = json_decode($response, true);{ "results": [ { "_id": "SaleStatuses$i8N34cQBWR", "value": 5000 }, { "_id": "SaleStatuses$zrP1MSVBoq", "value": 3150 }, { "_id": "SaleStatuses$E9cYlAlooc", "value": 1200 }, { "_id": null, "value": 0 } ]}קיבוץ לפי שם — דוט‑נוטציה דרך Pointer
Section titled “קיבוץ לפי שם — דוט‑נוטציה דרך Pointer”מייתר את שליפת טבלת ה‑lookup ואת החיבור בקוד.
curl -sS -G "https://api.mbapps.co.il/parse/classes-aggregate/Sales" \ -H "X-Parse-Application-Id: $APP_ID" \ -H "X-Parse-API-Key: $API_KEY" \ --data-urlencode 'group={"sum":"Total"}' \ --data-urlencode 'groupby=SaleStatusId.SaleStatuses.Name'const APP_ID = process.env.APP_ID, API_KEY = process.env.API_KEY;
const params = new URLSearchParams({ group: '{"sum":"Total"}', groupby: 'SaleStatusId.SaleStatuses.Name',});
const res = await fetch(`https://api.mbapps.co.il/parse/classes-aggregate/Sales?${params}`, { headers: { 'X-Parse-Application-Id': APP_ID, 'X-Parse-API-Key': API_KEY, },});const data = await res.json();import os, requests
APP_ID = os.environ["APP_ID"]API_KEY = os.environ["API_KEY"]
res = requests.get( "https://api.mbapps.co.il/parse/classes-aggregate/Sales", headers={ "X-Parse-Application-Id": APP_ID, "X-Parse-API-Key": API_KEY, }, params={ "group": '{"sum":"Total"}', "groupby": "SaleStatusId.SaleStatuses.Name", },)data = res.json()<?php$appId = getenv('APP_ID');$apiKey = getenv('API_KEY');
$query = http_build_query([ 'group' => '{"sum":"Total"}', 'groupby' => 'SaleStatusId.SaleStatuses.Name',]);
$ch = curl_init();curl_setopt_array($ch, [ CURLOPT_URL => "https://api.mbapps.co.il/parse/classes-aggregate/Sales?$query", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "X-Parse-Application-Id: $appId", "X-Parse-API-Key: $apiKey", ],]);$response = curl_exec($ch);curl_close($ch);$data = json_decode($response, true);{ "results": [ { "_id": "פגישת מצגת", "value": 5000 }, { "_id": "הושלמה", "value": 3150 }, { "_id": "חדש", "value": 1200 }, { "value": 0 } ]}התבנית: <PointerField>.<TargetClass>.<TargetField>, אותה דוט‑נוטציה שבדוחות ובטריגרים. ראו סוגי נתונים.
סינון, מיון והגבלה
Section titled “סינון, מיון והגבלה”curl -sS -G "https://api.mbapps.co.il/parse/classes-aggregate/Sales" \ -H "X-Parse-Application-Id: $APP_ID" \ -H "X-Parse-API-Key: $API_KEY" \ --data-urlencode 'where={"ClosingDate":{"$gte":{"__type":"Date","iso":"2026-01-01T00:00:00.000Z"}}}' \ --data-urlencode 'group={"sum":"Total"}' \ --data-urlencode 'groupby=OwnerId._User.name' \ --data-urlencode 'order=-value' \ --data-urlencode 'limit=10'const APP_ID = process.env.APP_ID, API_KEY = process.env.API_KEY;
const params = new URLSearchParams({ where: '{"ClosingDate":{"$gte":{"__type":"Date","iso":"2026-01-01T00:00:00.000Z"}}}', group: '{"sum":"Total"}', groupby: 'OwnerId._User.name', order: '-value', limit: '10',});
const res = await fetch(`https://api.mbapps.co.il/parse/classes-aggregate/Sales?${params}`, { headers: { 'X-Parse-Application-Id': APP_ID, 'X-Parse-API-Key': API_KEY, },});const data = await res.json();import os, requests
APP_ID = os.environ["APP_ID"]API_KEY = os.environ["API_KEY"]
res = requests.get( "https://api.mbapps.co.il/parse/classes-aggregate/Sales", headers={ "X-Parse-Application-Id": APP_ID, "X-Parse-API-Key": API_KEY, }, params={ "where": '{"ClosingDate":{"$gte":{"__type":"Date","iso":"2026-01-01T00:00:00.000Z"}}}', "group": '{"sum":"Total"}', "groupby": "OwnerId._User.name", "order": "-value", "limit": "10", },)data = res.json()<?php$appId = getenv('APP_ID');$apiKey = getenv('API_KEY');
$query = http_build_query([ 'where' => '{"ClosingDate":{"$gte":{"__type":"Date","iso":"2026-01-01T00:00:00.000Z"}}}', 'group' => '{"sum":"Total"}', 'groupby' => 'OwnerId._User.name', 'order' => '-value', 'limit' => '10',]);
$ch = curl_init();curl_setopt_array($ch, [ CURLOPT_URL => "https://api.mbapps.co.il/parse/classes-aggregate/Sales?$query", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "X-Parse-Application-Id: $appId", "X-Parse-API-Key: $apiKey", ],]);$response = curl_exec($ch);curl_close($ch);$data = json_decode($response, true);עשרת אנשי המכירות עם ההיקף הגדול ביותר, מעסקאות שמועד סגירתן מ‑2026. order מקבל value, -value או _id.
הרשאות
Section titled “הרשאות”האגרגציה אינה דורשת Master Key. היא מכבדת את הרשאות הטבלה כמו כל שליפה אחרת:
| האישור | התוצאה |
|---|---|
| Master Key / API Key | עובד |
Session Token של משתמש עם הרשאת find על הטבלה |
עובד |
| Application Id בלבד, או משתמש בלי תפקיד | {"code":119,"error":"Permission denied for action find on class Sales."} |
בקיבוץ דוט‑נוטציה צריך find גם על מחלקת היעד של ה‑Pointer, לא רק על הטבלה שמקבצים.
אל תריצו אגרגציה מהדפדפן עם מפתח: המפתח שפותח אותה פותח גם את כל השאר. הדפוס: שרת ביניים שמחזיק את המפתח, מריץ, ומחזיר ללקוח מספרים בלבד.
שרת ביניים
Section titled “שרת ביניים”"""דוח פייפליין: סכום ומספר עסקאות לפי שלב, עם שמות בעברית.המפתח נשאר בשרת; הלקוח מקבל JSON מוכן."""import json, os, requests
API = "https://api.mbapps.co.il/parse"H = {"X-Parse-Application-Id": os.environ["MB_APP_ID"], "X-Parse-API-Key": os.environ["MB_API_KEY"]} # ממנהל סודות, לא מקובץ
def pipeline_report(from_iso: str) -> list[dict]: common = { "where": json.dumps({"createdAt": {"$gte": {"__type": "Date", "iso": from_iso}}}), "groupby": "SaleStatusId.SaleStatuses.Name", } def agg(op): params = {**common, "group": json.dumps(op)} r = requests.get(f"{API}/classes-aggregate/Sales", headers=H, params=params, timeout=60) r.raise_for_status() return {row.get("_id"): row["value"] for row in r.json()["results"]}
totals = agg({"sum": "Total"}) # אופרטור אחד לכל קריאה — counts = agg({"sum": 1}) # ולכן סכום וספירה הם שתי קריאות
return [{"stage": stage or "— ללא שלב —", "total": total, "deals": counts.get(stage, 0)} for stage, total in sorted(totals.items(), key=lambda kv: -kv[1])]
if __name__ == "__main__": for row in pipeline_report("2026-01-01T00:00:00.000Z"): print(f'{row["stage"]:<24} {row["total"]:>12,} ({row["deals"]} עסקאות)')שלוש מגבלות
Section titled “שלוש מגבלות”1 · אופרטור אחד לכל קריאה
Section titled “1 · אופרטור אחד לכל קריאה”אין סכום וגם ספירה בקריאה אחת; לכן הדוגמה למעלה מריצה שתי קריאות ומחברת בקוד.
בשכבת ה‑MCP הכלי Aggregate-Data גמיש יותר: group מקבל תווית ({"total":{"sum":"Total"}}, והערך חוזר תחת התווית במקום value), ואף שתי תוויות בקריאה אחת ({"total":{"sum":"Total"},"n":{"sum":1}}, למרות שסכימת הכלי מצהירה על אחת); groupby יכול להיות מחרוזת או אובייקט לקיבוץ רב‑מימדי ({"stage":"SaleStatusId.SaleStatuses.Name","month":{"mm":"ClosingDate"}}), כולל קיבוץ לפי תאריך: hour, dow, mm, q, q/yy, yy עובדים, m/yy נכשל (Invalid parameter for groupby date). ה‑where של הכלי חסום בוולידציית fieldName, ולכן סינון נעשה בינתיים רק ב‑REST.
2 · classes-aggregate אינו נתיב מתועד ב‑Parse
Section titled “2 · classes-aggregate אינו נתיב מתועד ב‑Parse”3 · שדה מחושב לא קיים
Section titled “3 · שדה מחושב לא קיים”אין שדות מחושבים ברמת הסכימה ואין “סכום שורות” אוטומטי. חישוב חוצה‑רשומות שצריך להישמר על רשומה (עמלות מדורגות, סיכומי גלגול) הוא פונקציית צד שרת.
המשך מכאן
Section titled “המשך מכאן”- שאילתות · מפת הטבלאות · אימות והרשאות
- שרת ה‑MCP —
Aggregate-Dataכשכבה גבוהה יותר - מגבלות ומכסות