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​