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 = await 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 = await create({
schema: {
id: 'string',
type: 'string',
design: 'string',
color: 'string',
rank: 'number',
isPromoted: 'boolean',
},
})
const ids = await 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 = await 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 = await 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 = await 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 interface
interface Doc extends Document {
type: string
design: string
rank: number
color: string
isPromoted: boolean
}
// The aggregation interface
interface AggregationValue {
type: string
design: string
colors: string[]
ranks: number[]
isPromoted: boolean
}
const results = await 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.