|
1 | 1 | # rushdb-docs
|
2 | 2 |
|
| 3 | +## 1.15.0 |
| 4 | + |
| 5 | +### Minor Changes |
| 6 | + |
| 7 | +- 7f19708: ## Summary |
| 8 | + Adds first-class grouping support to the Search API (`groupBy`) across core, JavaScript SDK, dashboard, website, and docs. Also standardizes terminology (`uniq` -> `unique`), refines aggregation semantics, and updates documentation with a dedicated grouping concept page. |
| 9 | + |
| 10 | + *** |
| 11 | + |
| 12 | + ## ✨ New Feature: `groupBy` Clause |
| 13 | + |
| 14 | + You can now pivot / summarize search results by one or more keys. Keys reference an alias + property (root alias is implicitly `$record`). |
| 15 | + |
| 16 | + Example (JS SDK): |
| 17 | + |
| 18 | + ```ts |
| 19 | + const dealsByStage = await db.records.find({ |
| 20 | + labels: ['HS_DEAL'], |
| 21 | + aggregate: { |
| 22 | + count: { fn: 'count', alias: '$record' }, |
| 23 | + avgAmount: { fn: 'avg', field: 'amount', alias: '$record' } |
| 24 | + }, |
| 25 | + groupBy: ['$record.dealstage'], |
| 26 | + orderBy: { count: 'desc' } |
| 27 | + }) |
| 28 | + // → rows like: [{ dealstage: 'prospecting', count: 120, avgAmount: 3400 }, ...] |
| 29 | + ``` |
| 30 | + |
| 31 | + Key capabilities: |
| 32 | + |
| 33 | + - Multiple grouping keys: `groupBy: ['$record.category', '$record.active']` |
| 34 | + - Group by related aliases (declare alias in `where` traversal first) |
| 35 | + - Works with all existing aggregation functions (count, sum, avg, min, max, collect, similarity, etc.) |
| 36 | + - Ordering applies to aggregated rows when `groupBy` is present |
| 37 | + - Requires at least one aggregation entry to take effect |
| 38 | + |
| 39 | + Result shape when using `groupBy`: each row contains only the grouping fields plus aggregated fields (raw record bodies are not returned unless you also aggregate them via `collect`). |
| 40 | + |
| 41 | + *** |
| 42 | + |
| 43 | + ## 🔄 Aggregation & Semantics Updates |
| 44 | + |
| 45 | + - `collect` results are unique by default. Set `unique: false` to retain duplicates. |
| 46 | + - Aggregation entries now consistently use the `unique` flag (replacing legacy `uniq`). |
| 47 | + - Distinct handling for grouped queries unified under the `unique` option. |
| 48 | + - Improved Cypher generation: clearer alias usage and property quoting; vector similarity function formatting tightened. |
| 49 | + - Added internal `PROPERTY_WILDCARD_PROJECTION` support (enables future selective projections) – not yet a public API, but impacts generated queries. |
| 50 | + |
| 51 | + *** |
| 52 | + |
| 53 | + ## 💥 Breaking Changes |
| 54 | + |
| 55 | + | Area | Change | Action Required | |
| 56 | + | ----------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | |
| 57 | + | Schema field definitions | `uniq` key renamed to `unique` | Rename all occurrences (`{ uniq: true }` → `{ unique: true }`). | |
| 58 | + | Aggregation definitions | Aggregator option `uniq` renamed to `unique` | Update custom aggregation objects (`uniq: false` → `unique: false`). | |
| 59 | + | Result shape (when using `groupBy`) | Raw record objects no longer returned automatically | If you previously expected full records, add a `collect` aggregation (e.g. `rows: { fn: 'collect', alias: '$record' }`). | |
| 60 | + | Default uniqueness for `collect` | Now unique by default | Add `unique: false` if you require duplicates. | |
| 61 | + | Internal alias constant | `DEFAULT_RECORD_ALIAS` → `ROOT_RECORD_ALIAS` | Only relevant if you referenced internal constants (avoid relying on these). | |
| 62 | + |
| 63 | + If any code or saved JSON queries still send `uniq`, they will now fail unless a compatibility shim exists (none added in this release). Treat this as a required migration. |
| 64 | + |
| 65 | + *** |
| 66 | + |
| 67 | + ## 🛠 Migration Guide |
| 68 | + |
| 69 | + 1. Rename all schema property options: |
| 70 | + - Before: `email: { type: 'string', uniq: true }` |
| 71 | + - After: `email: { type: 'string', unique: true }` |
| 72 | + 2. Update aggregation specs: |
| 73 | + - Before: `names: { fn: 'collect', field: 'name', alias: '$user', uniq: true }` |
| 74 | + - After: `names: { fn: 'collect', field: 'name', alias: '$user' }` (omit `unique` if true) |
| 75 | + 3. Reintroduce duplicate collection (if needed): add `unique: false`. |
| 76 | + 4. When adopting `groupBy`, ensure at least one aggregation is defined; queries with only `groupBy` are invalid. |
| 77 | + 5. Adjust consumer code to handle aggregated row shape instead of full record instances. |
| 78 | + 6. For hierarchical drill‑downs: group at the parent level; use nested `collect` for children instead of adding child keys to `groupBy`. |
| 79 | + |
| 80 | + ### Example Migration (JS) |
| 81 | + |
| 82 | + ```diff |
| 83 | + aggregate: { |
| 84 | + - employeeNames: { fn: 'collect', field: 'name', alias: '$employee', uniq: true }, |
| 85 | + + employeeNames: { fn: 'collect', field: 'name', alias: '$employee' }, |
| 86 | + } |
| 87 | + ``` |
| 88 | + |
| 89 | + ### Adding Grouping |
| 90 | + |
| 91 | + ```ts |
| 92 | + const deptProjects = await db.records.find({ |
| 93 | + labels: ['DEPARTMENT'], |
| 94 | + where: { PROJECT: { $alias: '$project' } }, |
| 95 | + aggregate: { |
| 96 | + projectCount: { fn: 'count', alias: '$project' }, |
| 97 | + projects: { fn: 'collect', field: 'name', alias: '$project', unique: true } |
| 98 | + }, |
| 99 | + groupBy: ['$record.name'], |
| 100 | + orderBy: { projectCount: 'desc' } |
| 101 | + }) |
| 102 | + ``` |
| 103 | + |
| 104 | + *** |
| 105 | + |
| 106 | + ## 📘 Documentation |
| 107 | + |
| 108 | + - Added dedicated concept page: `concepts/search/group-by` centralizing all grouping patterns (multi-key, alias-based, nested, uniqueness nuances, limitations). |
| 109 | + - Updated Python, REST, and TypeScript SDK "Get Records" guides with concise grouping sections linking to the concept page. |
| 110 | + - Refactored Aggregations doc to avoid duplication and point to new grouping guide. |
| 111 | + - Standardized examples to use `unique` terminology. |
| 112 | + |
| 113 | + *** |
| 114 | + |
| 115 | + ## 🧪 Tests & Internal Refactors |
| 116 | + |
| 117 | + - Extended aggregate & query builder tests to cover `groupBy` permutations (single key, multi-key, alias grouping, collect uniqueness flags). |
| 118 | + - Parser adjustments for: property quoting, alias resolution, vector similarity formatting, optional matches, and root alias constant rename. |
| 119 | + - Introduced `AggregateContext` enhancements to track grouping state. |
| 120 | + |
| 121 | + *** |
| 122 | + |
| 123 | + ## ⚠️ Edge Cases & Notes |
| 124 | + |
| 125 | + - An empty `groupBy` array is ignored; supply at least one key. |
| 126 | + - Supplying a group key for a property that does not exist yields rows with `null` for that column (consistent with underlying graph behavior) – validate upstream if needed. |
| 127 | + - Ordering by an aggregation that isn't defined will be rejected; always define the aggregate you sort by. |
| 128 | + - To sort by a group key, just reference it in `orderBy` using the property name (without alias prefix) after grouping. |
| 129 | + |
| 130 | + *** |
| 131 | + |
| 132 | + ## ✅ Quick Checklist |
| 133 | + |
| 134 | + | Task | Done? | |
| 135 | + | ------------------------------------------------------------------- | ----- | |
| 136 | + | Renamed all `uniq` → `unique` in schema & aggregations | | |
| 137 | + | Reviewed any `collect` aggregations for unintended de-duplication | | |
| 138 | + | Added `unique: false` where duplicates are required | | |
| 139 | + | Updated UI / API consumers for aggregated row shape under `groupBy` | | |
| 140 | + | Added `collect` fields if raw record snapshots are still needed | | |
| 141 | + | Added / validated ordering under grouped queries | | |
| 142 | + |
| 143 | + *** |
| 144 | + |
| 145 | + ## Feedback |
| 146 | + |
| 147 | + Please report any unexpected behavior with grouped queries (especially multi-key or alias-based grouping) so we can refine edge case handling in upcoming releases. |
| 148 | + |
| 149 | + *** |
| 150 | + |
| 151 | + ## TL;DR |
| 152 | + |
| 153 | + Use `groupBy` + `aggregate` to pivot results; rename `uniq` → `unique`; `collect` is now unique by default; aggregated queries return row sets, not raw records. |
| 154 | + |
3 | 155 | ## 1.14.2
|
4 | 156 |
|
5 | 157 | ### Patch Changes
|
|
0 commit comments