Grouping
Orama supports groupBy
operations.
That allows you to group results in groups calculating an aggregation on the item that belongs to the same bucket.
const results = search(db, { term: "t-shirt", groupBy: { properties: ["design"], // required: property on which we want to group on maxResult: 1, // optional: for every group, how many results we want reduce: { // optional: customize the aggregation logic reducer: Function, getInitialValue: Function, }, },});
By default, Orama doesn’t limit the number of items inside a group.
By default, Orama groups all the matched documents into an array.
Simple usage
If we consider the following schema:
const db = create({ schema: { id: "string", type: "string", design: "string", color: "string", rank: "number", isPromoted: "boolean", },});const ids = insertMultiple(db, [ { id: "0", type: "t-shirt", design: "A", color: "blue", rank: 3, isPromoted: true, }, { id: "1", type: "t-shirt", design: "A", color: "green", rank: 5, isPromoted: false, }, { id: "2", type: "t-shirt", design: "A", color: "red", rank: 4, isPromoted: false, }, { id: "3", type: "t-shirt", design: "B", color: "blue", rank: 4, isPromoted: false, }, { id: "4", type: "t-shirt", design: "B", color: "green", rank: 4, isPromoted: true, }, { id: "5", type: "t-shirt", design: "B", color: "white", rank: 5, isPromoted: false, }, { id: "6", type: "t-shirt", design: "B", color: "gray", rank: 5, isPromoted: true, }, { id: "7", type: "sweatshirt", design: "A", color: "yellow", rank: 3, isPromoted: true, }, { id: "8", type: "sweatshirt", design: "A", color: "green", rank: 4, isPromoted: false, },]);
We will be able to have the documents per design
ordered by rank
:
const results = search(db, { term: "t-shirt", groupBy: { properties: ["design"], // property on which we want to group on }, sortBy: { property: "rank", // inside a group, the result is ordered following this property order: "DESC", // with this order },});
If you want only the top-ranked document per design
, you can specify the maxResult
:
const results = search(db, { term: "t-shirt", groupBy: { properties: ["design"], maxResult: 1, // for every group, how many results we want }, sortBy: { property: "rank", order: "DESC", },});
The above query returns something like this:
{ groups: [ { values: ['A'], // list of the values the group is referring to result: [ { id: '1', score: 0, document: { ... } // the doc with id '1' } ] }, { values: ['B'], // list of the values the group is referring to result: [ { id: '5', score: 0, document: { ... } // the doc with id '5' } ] } ], // The other common properties like `hits` and `elapsed`}
You can group on multiple properties as follows:
const results = search(db, { term: "red t-shirt", groupBy: { properties: ["design", "rank", "isPromoted"], // group on the combination of the values }, sortBy: { property: "id", order: "ASC", },});
Custom reducer
Orama supports custom aggregator as follows:
// The document interfaceinterface Doc extends Document { type: string; design: string; rank: number; color: string; isPromoted: boolean;}// The aggregation interfaceinterface AggregationValue { type: string; design: string; colors: string[]; ranks: number[]; isPromoted: boolean;}
const results = search(db, { term: "red t-shirt", groupBy: { properties: ["type", "design"], // group on both properties reduce: { // the accumulator function reducer: ( values: ScalarSearchableValue[], acc: AggregationValue, item: Result ) => { const doc = item.document as Doc; acc.type ||= doc.type; acc.design ||= doc.design; acc.isPromoted ||= doc.isPromoted; acc.colors.push(doc.color); acc.ranks.push(doc.rank); return acc; }, // The initial value: this is called for every group getInitialValue: (): AggregationValue => ({ type: "", design: "", colors: [], ranks: [], isPromoted: false, }), }, }, sortBy: { property: "rank", order: "DESC", },});
Where the accumulator function receives the following parameters:
- the value of the current groups
- the accumulator returned by the previous invocation
- the item to accumulate
The reducer is called for every item for every group.