Grouping
Learn how to group search results in Orama.
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 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 = 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.
Last updated on