Sorting Syntax
CargoX supports flexible sorting for list queries. You can sort by single or multiple fields, in ascending or descending order, and even sort by properties within filtered collections.
Basic Syntax
To sort by a field, pass the field name to the orderBy parameter:
query {
orders(organizationId: 1, orderBy: "orderNumber") {
items {
orderNumber
created
}
}
}
Descending Order
To sort in descending order, prefix the field name with a minus sign (-):
query {
orders(organizationId: 1, orderBy: "-created") {
items {
orderNumber
created
}
}
}
Multiple Sort Fields
To sort by multiple fields, separate them with commas. The first field is the primary sort, the second is secondary, and so on:
query {
orders(organizationId: 1, orderBy: "orderType,orderNumber") {
items {
orderType
orderNumber
}
}
}
You can mix ascending and descending:
query {
orders(organizationId: 1, orderBy: "-created,orderNumber") {
items {
created
orderNumber
}
}
}
Sorting by Nested Properties
To sort by a property of a related entity, use dot notation:
query {
states(organizationId: 1, orderBy: "country.name") {
items {
stateCode
name
country {
name
}
}
}
}
Examples
| orderBy | Description |
|---|---|
country.name | Sort by the country's name |
-country.name | Sort by the country's name descending |
billToContact.name | Sort by the bill-to contact's name |
orderStatus.name | Sort by the order status name |
Sorting by Collection Properties
When sorting by a property within a collection (one-to-many relationship), the system uses the first item in the collection:
query {
commodities(organizationId: 1, orderBy: "orderCommodities.order.orderNumber") {
items {
description
}
}
}
Filtered Collection Sorting
For more precise control when sorting by collection properties, you can filter the collection before selecting the sort value. This is useful when entities have multiple related items of different types.
Syntax
collection[filterPath:filterValue].property
Where:
collection- The name of the collection propertyfilterPath- The path to the property to filter on (can include dots for nested properties)filterValue- The value to filter byproperty- The property to sort by after filtering
Examples
Sorting by a Specific Entity Type
Sort orders by the name of their "UltimateConsignee" entity:
query {
orders(organizationId: 1, orderBy: "orderEntities[entityType:UltimateConsignee].contact.name") {
items {
orderNumber
}
}
}
Sorting by a Specific Order Type
Sort commodities by the bill-to contact name of their "ParcelShipment" orders:
query {
commodities(organizationId: 1, orderBy: "orderCommodities[order.orderType:ParcelShipment].order.billToContact.name") {
items {
description
}
}
}
Sorting Countries by Specific State
Sort countries by the name of their state with code "CA":
query {
countries(organizationId: 1, orderBy: "states[stateCode:CA].name") {
items {
countryCode
name
}
}
}
Supported Filter Types
The filter value can be:
| Type | Example | Description |
|---|---|---|
| String | [type:ParcelShipment] | Exact string match |
| Enum | [entityType:UltimateConsignee] | Enum value (case-insensitive) |
| Integer | [priority:1] | Integer value |
| Boolean | [isActive:true] | Boolean value |
| GUID | [id:550e8400-e29b-41d4-a716-446655440000] | GUID value |
Nested Filter Paths
The filter path can include nested properties using dot notation:
query {
commodities(organizationId: 1, orderBy: "orderCommodities[order.orderType:ParcelShipment].order.billToContact.name") {
items {
description
}
}
}
Descending Order with Filtered Collections
Prefix with minus sign for descending order:
query {
orders(organizationId: 1, orderBy: "-orderEntities[entityType:Carrier].contact.name") {
items {
orderNumber
}
}
}
Multiple Sort Fields with Filtered Collections
Combine filtered collection sorting with other sort fields:
query {
commodities(organizationId: 1, orderBy: "description,orderCommodities[order.orderType:ParcelShipment].order.billToContact.name") {
items {
description
}
}
}
Handling No Matches
When no items in the collection match the filter, the sort value is treated as null. In ascending order, nulls appear first; in descending order, nulls appear last.
Sorting by Last Tracking Event
Orders and commodities expose a synthetic lastTrackingEvent sort path that ranks the entire result set by the "winner" tracking event directly at the SQL level — before rows are returned. This is distinct from the field-level getLastTrackingEvent resolver, which resolves one event per row after the list is fetched.
Basic Usage
Sort orders by their most recent tracking event date (descending — newest first):
query {
orders(organizationId: 1, orderBy: "-lastTrackingEvent.eventDate") {
items {
orderId
orderNumber
}
}
}
Sort ascending (oldest tracking event first):
query {
orders(organizationId: 1, orderBy: "lastTrackingEvent.eventDate") {
items {
orderId
orderNumber
}
}
}
Scoping by Event Definition
Use the [filterPath:filterValue] bracket syntax to restrict the sort to a specific event type:
query {
orders(
organizationId: 1
orderBy: "-lastTrackingEvent[eventDefinition.eventName:Departed].eventDate"
) {
items {
orderId
orderNumber
}
}
}
This sorts orders by the date of their most recent Departed event, ignoring all other event types.
Supported Sub-Paths
orderBy expression | Sorts by |
|---|---|
lastTrackingEvent.eventDate | COALESCE(EventDate, Created) of the winning event |
lastTrackingEvent.trackingEventId | TrackingEventId of the winning event |
lastTrackingEvent[eventDefinition.eventName:X].eventDate | COALESCE(EventDate, Created) filtered to event type X |
When the sub-path is .eventDate, the emitted SQL selector is COALESCE(winner.EventDate, winner.Created) — matching the canonical winner-picking rule — so the outer ORDER BY never sees null for events that only have a Created timestamp.
Winner-Picking Rule
The "winning" event is selected using the same canonical ordering used by the getLastTrackingEvent DataLoader:
COALESCE(EventDate, Created) DESC— most recent effective date winsTrackingEventId DESC— tie-breaker when two events share the same effective date
This ensures that SQL-level list sorting and per-row field resolution agree on which event is "the last".
Combining with Other Sort Fields
query {
orders(
organizationId: 1
orderBy: "-lastTrackingEvent[eventDefinition.eventName:Departed].eventDate,orderNumber"
) {
items {
orderId
orderNumber
}
}
}
Handling Orders with No Matching Event
When no tracking event matches (or the order has no events at all), the sort value is null. Null handling follows standard SQL behaviour: nulls sort last in descending order and first in ascending order.
Sorting by Custom Values (JSON Fields)
To sort by a custom value stored in a JSON field, use dot notation:
query {
orders(organizationId: 1, orderBy: "customValues.priority") {
items {
orderNumber
customValues
}
}
}
Case Sensitivity
Field names in sort expressions are case-insensitive:
# These are equivalent:
orderBy: "orderNumber"
orderBy: "OrderNumber"
orderBy: "ORDERNUMBER"
Complete Examples
Example 1: Sort Orders by Carrier Name
query {
orders(organizationId: 1, orderBy: "orderEntities[entityType:Carrier].contact.name") {
items {
orderNumber
orderEntities {
entityType
contact {
name
}
}
}
}
}
Example 2: Sort Commodities by Customer Name (from ParcelShipment orders)
query {
commodities(organizationId: 1, orderBy: "orderCommodities[order.orderType:ParcelShipment].order.billToContact.name") {
items {
commodityId
description
}
}
}
Example 3: Multiple Sort with Filtered Collection
query {
orders(
organizationId: 1
orderBy: "orderType,-orderEntities[entityType:UltimateConsignee].contact.name,orderNumber"
) {
items {
orderType
orderNumber
}
}
}
SQL Translation
The filtered collection sorting translates to efficient SQL subqueries. For example:
-- orderBy: "orderEntities[entityType:UltimateConsignee].contact.name"
ORDER BY (
SELECT c.name
FROM order_entities oe
JOIN contacts c ON oe.contact_id = c.contact_id
WHERE oe.order_id = o.order_id
AND oe.entity_type = 'UltimateConsignee'
LIMIT 1
)
This ensures optimal database performance even with complex sorting requirements.