דלגו לתוכן

או התחילו מנקודה בטוחה: אינדקס הכלים המלא · מפת הטבלאות המרכזיות

מערכת חדשה — 14 יום חינם

אגרגציות ב‑REST

עודכן 30.08.2026
GET /parse/classes-aggregate/{Table}

כשהשאלה היא “כמה” ולא “אילו” — אגרגציה. במקום למשוך 12,000 שורות ולסכום אותן בקוד, השרת מחזיר שורה אחת לכל קבוצה.

פרמטר טיפוס משמעות
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.

הפונקציה הצורה
סכום 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/avgthe type of the group aggregate field (<Field>) must be "Number"; שדה לא קיים ב‑groupbyInvalid 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 “הדוגמה הבסיסית — סכום עסקאות לפי שלב”
Bash
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'
JavaScript
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();
Python
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
<?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);
JSON
{
"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 ואת החיבור בקוד:

Bash
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'
JavaScript
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();
Python
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
<?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);
JSON
{
"results": [
{ "_id": "פגישת מצגת", "value": 5000 },
{ "_id": "הושלמה", "value": 3150 },
{ "_id": "חדש", "value": 1200 },
{ "value": 0 }
]
}

התבנית היא <PointerField>.<TargetClass>.<TargetField> — אותה דוט‑נוטציה שמשמשת בדוחות ובטריגרים. ראו סוגי נתונים.

Bash
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'
JavaScript
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();
Python
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
<?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.

האגרגציה אינה דורשת 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 “שרת ביניים — הדפוס המומלץ”
Python
"""
דוח פייפליין: סכום ומספר עסקאות לפי שלב, עם שמות בעברית.
המפתח נשאר בשרת; הלקוח מקבל 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”

אין שדות מחושבים ברמת הסכימה ואין “סכום שורות” אוטומטי. חישוב חוצה‑רשומות שצריך להישמר על רשומה (עמלות מדורגות, סיכומי גלגול) הוא פונקציית צד שרת — ראו פונקציות צד שרת.