You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor: simplify brand-vs-competitors to single view query with aggregate param
Replace the two-step PostgREST pattern (discover dates from
brand_presence_executions, then chunked .in() queries against the view)
with a single direct query using .gte()/.lte() date-range filters on
brand_vs_competitors_by_date. The regular VIEW supports WHERE pushdown
into partition-pruned scans, making the separate date discovery step
unnecessary.
Add aggregate=true query parameter that rolls up across
categoryName/regionCode server-side, producing one row per
(competitor, executionDate) — the shape the Market Tracking chart
needs directly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/llmo-brandalf-apis/brand-vs-competitors-api.md
+20-11Lines changed: 20 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -27,6 +27,7 @@ Returns aggregated competitor mention/citation data for a site. Internally perfo
27
27
|`model`| — | string | No |`chatgpt`| LLM model |
28
28
|`categoryName`|`category_name`| string | No | — | Filter by category name |
29
29
|`regionCode`|`region_code`, `region`| string | No | — | Filter by region code |
30
+
|`aggregate`| — | boolean | No |`false`| Roll up across categoryName/regionCode |
30
31
31
32
---
32
33
@@ -42,26 +43,34 @@ GET /org/44568c3e-efd4-4a7f-8ecd-8caf615f836c/brands/all/brand-presence/brand-vs
42
43
GET /org/44568c3e-efd4-4a7f-8ecd-8caf615f836c/brands/019cb903-1184-7f92-8325-f9d1176af316/brand-presence/brand-vs-competitors?siteId=c2473d89-e997-458d-a86d-b4096649c12b&startDate=2026-01-01&endDate=2026-03-31&categoryName=SEO®ionCode=US
43
44
```
44
45
45
-
---
46
+
**Aggregated for Market Tracking chart (one row per competitor per week):**
47
+
```
48
+
GET /org/44568c3e-efd4-4a7f-8ecd-8caf615f836c/brands/all/brand-presence/brand-vs-competitors?siteId=c2473d89-e997-458d-a86d-b4096649c12b&aggregate=true
49
+
```
46
50
47
-
## Internal Queries (PostgREST)
51
+
---
48
52
49
-
This endpoint performs two sequential PostgREST queries:
53
+
## Internal Query (PostgREST)
50
54
51
-
**Step 1 — Discover execution dates:**
52
-
- Queries `brand_presence_executions` table
53
-
- Selects `execution_date`, filtered by `organization_id`, `site_id`, `model`, date range (`gte`/`lte`), optionally `brand_id`
54
-
- Deduplicates dates client-side via `Set`
55
+
Single query against the `brand_vs_competitors_by_date` VIEW with date-range filters:
The VIEW is a regular (non-materialized) view — PostgreSQL pushes WHERE clauses through the GROUP BY into partition-pruned, index-covered scans on the source tables.
62
63
63
64
The underlying VIEW aggregates `executions_competitor_data` joined with `brand_presence_executions` and `organizations`, grouping by competitor (using `COALESCE(parent_company, competitor)` for fallback).
64
65
66
+
### Aggregation mode
67
+
68
+
By default, the response returns rows at `(competitor, executionDate, categoryName, regionCode)` granularity.
69
+
70
+
With `aggregate=true`, the server rolls up across `categoryName`/`regionCode` and returns one row per `(competitor, executionDate)` — the shape the **Market Tracking chart** needs directly. Aggregated rows omit `categoryName` and `regionCode`.
71
+
72
+
Category/region filters still apply *before* aggregation, so `aggregate=true&categoryName=SEO` returns chart-ready totals scoped to the SEO category.
0 commit comments