Skip to main content

Associate objects by a key

In this guide, we will build a simple function for creating a map that collects a structure based on a specific key. This is a standard pattern when working with many-to-one relations.

Say that you have, for example, the entity relations:

entity house {
key id: integer;
color: text;

entity street {
key address: text;

entity street_house {
key house;
index street;

For this relation, each house is unique and lives on a street, but each street can contain several houses. If we want to create a query that returns all houses grouped by their street, we'd like to get the following signature:

query get_houses_by_street(): map<text, list<struct<house>>>

Each entry in the map has the address as a key and a list of house-structs as values. Performing a database query using the at-operator, we can at most get a list<text, struct<house>>:

val house_list: list<(text, struct<house>)> = street_house @* {} ( .street.address, .house.to_struct() );

How do we create a map for this structure? Luckily, rell has a few annotations to aggregate the results into collections. @group is used to specify what we want to group with, and @list or @set can specify the target collection type.

We can now collect the results in a slightly better structure:

val house_streets: list<(text, list<struct<house>>)> =
street_house @* {} ( @group .street.address, @list .house.to_struct() );

The @group annotation tells the ORM that we want to group the results using the street address as the key, and the @list annotation collects all houses on the same street.

But we can directly convert the resulting type into a map using another annotation provided by Rell ORM, called @map:

val houses_by_street = house_streets @ {} ( @map $ );

This is another at-expression that works on a collection. In the what-clause, we use @map to treat each entry as a map entry.

Using this approach, we can optimize the database query for obtaining the results and convert them into a map structure using fewer lines of code and in an optimized way.