Skip to main content

Query Expressions

Query expressions provide a SQL-like syntax for filtering, transforming, and aggregating data in Ballerina. They work with arrays, maps, streams, tables, and XML, making them a core tool for data transformation in integration workflows.

Basic syntax

var result = from var item in collection
where condition
select expression;

Clauses reference

ClausePurposeRequired
fromDefine the input source and iteration variableYes
whereFilter items based on a conditionNo
letBind intermediate variablesNo
order bySort resultsNo
limitRestrict the number of resultsNo
selectTransform each item (produces a list)One of select or collect
collectAggregate all items into a single valueOne of select or collect
joinJoin with another collectionNo
on conflictHandle key conflicts in table resultsNo

from clause

Iterate over arrays, maps, strings, streams, tables, or XML:

// Array
from var item in [1, 2, 3, 4, 5]

// Map
from var [key, value] in myMap.entries()

// String (characters)
from var char in "hello"

// Table
from var row in employeeTable

// XML children
from var elem in xmlValue/<name>

// Stream
from var event in eventStream

// Integer range
from var i in 0 ..< 10

Multiple from clauses (Cartesian product)

json[] combinations = from var color in ["red", "blue"]
from var size in ["S", "M", "L"]
select {color, size};
// [{color: "red", size: "S"}, {color: "red", size: "M"}, ...]

where clause

Filter items based on a boolean condition:

int[] evenNumbers = from var n in [1, 2, 3, 4, 5, 6]
where n % 2 == 0
select n;
// [2, 4, 6]
type Order record {
string id;
string status;
decimal amount;
};

Order[] highValueOrders = from var order in orders
where order.status == "completed"
where order.amount > 1000.0
select order;

let clause

Bind intermediate computed values:

type OrderSummary record {
string id;
decimal total;
string tier;
};

OrderSummary[] summaries = from var order in orders
let decimal total = order.subtotal + order.tax
let string tier = total > 500.0 ? "premium" : "standard"
select {
id: order.id,
total: total,
tier: tier
};

select clause

Transform each item into a new value:

// Extract field
string[] names = from var customer in customers
select customer.name;

// Transform to new record
type CustomerDTO record {
string fullName;
string email;
};

CustomerDTO[] dtos = from var c in customers
select {
fullName: c.firstName + " " + c.lastName,
email: c.email
};

collect clause

Aggregate all items into a single result:

// Sum
int total = from var item in lineItems
collect sum(item.amount);

// Count
int count = from var item in lineItems
where item.status == "active"
collect count();

// Build a string
string csv = from var name in names
collect string:'join(",", ...names);

Aggregate functions for collect

FunctionDescriptionExample
sum(expr)Sum of numeric valuescollect sum(item.price)
count()Count of itemscollect count()
avg(expr)Average of numeric valuescollect avg(item.score)
min(expr)Minimum valuecollect min(item.price)
max(expr)Maximum valuecollect max(item.price)

join clause

Join two collections on a condition:

type OrderWithCustomer record {
string orderId;
string customerName;
decimal amount;
};

OrderWithCustomer[] enriched = from var order in orders
join var customer in customers
on order.customerId equals customer.id
select {
orderId: order.id,
customerName: customer.name,
amount: order.amount
};

Outer join

Use outer join when the right side may not have a match:

var results = from var order in orders
outer join var customer in customers
on order.customerId equals customer.id
select {
orderId: order.id,
customerName: customer?.name ?: "Unknown"
};

order by clause

Sort results by one or more fields:

Order[] sorted = from var order in orders
order by order.amount descending
select order;

// Multiple sort keys
var sorted = from var emp in employees
order by emp.department ascending, emp.salary descending
select emp;

limit clause

Restrict the number of results:

Order[] top10 = from var order in orders
order by order.amount descending
limit 10
select order;

on conflict clause

Handle key conflicts when the result is a table:

table<Employee> key(id) empTable = table key(id) from var emp in employees
select emp
on conflict error("Duplicate employee ID");

Query actions

Use do instead of select to perform side effects:

from var order in orders
where order.status == "pending"
do {
log:printInfo("Processing order", orderId = order.id);
check processOrder(order);
};

Integration examples

Transform API response

json apiResponse = check client->get("/api/products");
json[] products = check apiResponse.ensureType();

type ProductSummary record {
string name;
decimal price;
boolean inStock;
};

ProductSummary[] summaries = from var product in products
let json stock = check product.inventory
where check product.active == true
select {
name: check product.name,
price: check product.price,
inStock: check stock.quantity > 0
};

Aggregate Kafka events

decimal totalRevenue = from var event in revenueEvents
where event.region == "us-east"
collect sum(event.amount);

What's next