Join Expressions
Join expressions allow you to sort and filter by properties of related entities that are referenced through custom value foreign keys. This is useful when a custom field stores an ID that points to another entity (such as a contact, order, or country), and you want to sort or filter by a property on that related entity rather than by the raw ID value.
Syntax
customValues.key->entity.property
| Part | Description |
|---|---|
customValues.key | Path to the JSONB field containing the foreign key value |
-> | Join operator |
entity | Alias of the target entity (case-insensitive) |
property | Single-level property on the target entity to sort/filter by |
Example
customValues.carrierId->contact.name
This reads the carrierId value from the entity's customValues, joins to the Contacts table by matching ContactId, and resolves to the contact's Name property.
Supported Entities
| Alias | Entity | Join Key | Key Type | DbSet |
|---|---|---|---|---|
contact | Contact | ContactId | int | Contacts |
order | Order | OrderId | int | Orders |
modeOfTransportation | ModeOfTransportation | ModeOfTransportationId | int | ModeOfTransportations |
country | Country | CountryCode | string | Countries |
terminal | Terminal | TerminalId | int | Terminals |
contactAddress | ContactAddress | ContactAddressId | int | ContactAddresses |
port | Port | PortId | string | Ports |
Entity aliases are case-insensitive (Contact, contact, and CONTACT all resolve to the same entity).
How It Works
The join expression builds a correlated subquery at the database level. For example:
customValues.carrierId->contact.name
Translates to the equivalent of:
(SELECT c."Name"
FROM "Contacts" c
WHERE c."ContactId" = jsonb_extract_path_int(x."CustomValues", 'carrierId')
LIMIT 1)
The steps are:
- Extract the key from the JSONB
customValuescolumn using the appropriate extraction method (JsonbExtractPathIntfor integer keys,JsonbExtractPathTextfor string keys) - Query the target DbSet with a
Whereclause matching the entity's primary key to the extracted value - Select the target property (e.g.,
Name) - Wrap value types in Nullable — if the target property is a non-nullable value type (e.g.,
int), the result is cast to its nullable equivalent (int?) so thatNULLis returned when no row matches instead of the type's default value - Take the first result using
FirstOrDefault()
Sorting with Join Expressions
Use join syntax in the orderBy parameter:
query {
orders(
organizationId: 1
orderBy: "customValues.carrierId->contact.name"
) {
items { orderId }
}
}
Location custom values can sort by contact-address names when they store a ContactAddressId:
orderBy: "customValues.deliveryLocationId->contactAddress.name"
orderBy: "customValues.returnLocationId->contactAddress.name"
Descending sort:
orderBy: "-customValues.carrierId->contact.name"
Multi-field sort with joins:
orderBy: "-created,customValues.carrierId->contact.name"
Terminal and port references stored in custom values can be sorted the same way:
orderBy: "customValues.terminalId->terminal.name"
orderBy: "-customValues.returnLocationId->terminal.name"
orderBy: "customValues.portId->port.name"