Data Access & Collections
Master dynamic data binding, the one record = one document architecture, collection filtering, sorting, grouping, nested hierarchies, and collectionId scoping.
ComposeIt is designed from the ground up for high-precision document automation. Understanding how data binds to templates—from simple single-variable replacements to complex multi-tiered nested collections—is essential for building robust reports, invoices, contracts, and statements.
The "One Record = One Document" Architecture
The fundamental mental model of ComposeIt is One Record = One Document:
When you trigger a document render, whether via the ComposeIt REST API, Webhook, Zapier, or the Editor test runner. The payload root object (root) represents exactly one generated document instance.
Data Shaping Best Practices
To ensure predictable document composition, structure your payload so that the document metadata sits on the root object, while all recurring or one-to-many tabular records are represented as JSON arrays of objects.
{
"invoiceNumber": "INV-2026-0042",
"issueDate": "2026-09-24",
"dueDate": "2026-10-24",
"client": {
"name": "Acme Global Dynamics",
"email": "billing@acmeglobal.com",
"country": "Germany",
"isVatExempt": false
},
"summary": {
"subtotal": 12500.0,
"taxRate": 0.19,
"total": 14875.0
},
"lineItems": [
{
"id": "item-101",
"sku": "SRV-DEV-01",
"description": "Custom API Gateway Architecture",
"hours": 40,
"rate": 175,
"discount": 0.1,
"amount": 6300.0
},
{
"id": "item-102",
"sku": "SRV-SEC-03",
"description": "SOC2 Compliance & Pen-testing Audit",
"hours": 35,
"rate": 180,
"discount": 0.0,
"amount": 6300.0
}
]
}Batch Generation via API
When generating PDFs in bulk (e.g. 500 invoices at the end of the month), pass
an array of these root record objects to the batch rendering endpoint: POST /api/export/batch. Each item in the array is merged against the template
independently to produce a dedicated PDF.
Working with Collections
A Collection in ComposeIt turns any visual element or container into a repeated template block. You can bind collections to:
- Table rows (
<tr>) for compact tabular line items - Cards & Grids (
<div>/ flex blocks) for product catalogs or executive profiles
Binding a Component to a Collection
- Select the component you wish to repeat (e.g. a table row
<tr>). - Open the Traits panel on the right sidebar.
- Click Edit Logic to select a collection to loop over. Each component type can be looped over by clicking on it then accessing the context menu then clicking Wrap with collection.
- In the Data Path selector, enter or select the array path relative to the root (e.g.
root.lineItems). - Within the repeated component, bind child text elements directly using path selectors or custom path strings.
Collection Operations: Sorting, Filtering & Grouping
ComposeIt allows you to transform raw data at the collection level without needing backend pre-processing.
1. Sorting
Configure multi-column sorting directly inside the Collection Traits:
| Property | Description | Example |
|---|---|---|
| Sort Field | Path to the target sort key | amount or date |
| Direction | Ascending (ASC) or Descending (DESC) | DESC |
| Type | Number, String, or Date | Number |
You can chain multiple sort rules (e.g. Sort by category ASC, then by amount DESC).
2. Filtering
Filters allow you to suppress or display items based on dynamic logic. Filters can be configured using visual rule builders:
Common filtering use cases:
- Filter out refunded or zero-value transactions.
- Filter line items by region or department for targeted sub-reports.
- Separate paid vs. overdue invoices into two separate visual tables on the same page.
3. Grouping
Grouping allows you to split a single flat array into hierarchical sub-collections based on a categorical key.
For example, given a flat list of department expenses:
[
{ "dept": "Engineering", "item": "Cloud Compute", "cost": 4200 },
{ "dept": "Engineering", "item": "CI/CD Pipeline", "cost": 850 },
{ "dept": "Marketing", "item": "AdWords Campaign", "cost": 6100 },
{ "dept": "Marketing", "item": "Conference Booth", "cost": 3400 }
]When you set Group By to dept, ComposeIt generates:
- An outer group repeater with access to
group.key(e.g."Engineering"). - An inner items collection containing all matching records for that specific key.
- Built-in aggregation helpers like
SUM(group.items, "cost").
Conditional Rendering
Every element in ComposeIt can be wrapped in a Condition to dynamically toggle its visibility based on data values.
Common Conditions
- Tax & Discount Row Suppression: Hide the discount row if
root.summary.discount == 0. - Payment Method Badges: Display a wire transfer instructions block only if
root.paymentMethod == "wire". - Disclaimers & Legal Notes: Show state-specific compliance clauses based on
root.client.state.
Nested Collections & Hierarchies
Complex business documents often require multiple layers of iteration. Typical examples include:
- Order Statements: Order → Line Items → Product Options / Modifiers
- Departmental Audits: Division → Cost Centers → Line Item Expenses
- Event Itineraries: Days → Tracks → Sessions → Speakers
Hierarchical Data Structure Example
{
"accountName": "Enterprise Logistics Corp",
"billingPeriod": "Q3 2026",
"warehouses": [
{
"id": "wh-eu-west",
"name": "Frankfurt Central Hub",
"manager": "Lena Schmidt",
"shipments": [
{
"id": "ship-901",
"carrier": "DHL Express",
"dispatchDate": "2026-08-14",
"packages": [
{ "trackingNumber": "DHL-88912", "weightKg": 14.5, "fee": 120 },
{ "trackingNumber": "DHL-88913", "weightKg": 8.2, "fee": 85 }
]
},
{
"id": "ship-902",
"carrier": "FedEx Freight",
"dispatchDate": "2026-08-16",
"packages": [
{ "trackingNumber": "FX-44019", "weightKg": 120.0, "fee": 450 }
]
}
]
}
]
}Understanding collectionId & Scope Disambiguation
When working with nested repeaters, a common point of confusion in document templating is variable name collisions.
Notice in the JSON above:
warehousehas anid("wh-eu-west")shipmenthas anid("ship-901")
If you place a text element inside the inner package repeater and request id, which identifier should be printed? The warehouse ID, the shipment ID, or an error?
How collectionId Resolves Context
To eliminate ambiguity, ComposeIt assigns a unique, immutable collectionId to every collection wrapper component in the canvas.
Definitive Path Syntax
Inside any nested block, variables can be addressed with absolute precision using the collectionId prefix:
| Collection Key | Collection ID |
|---|---|
| warehouses | collReF4xw |
| shipments | collGt9dkd |
| packages | collDkdke9 |
| Scope Level | Path Expression | Resolved Value |
|---|---|---|
| Document Root | root.billingPeriod | "Q3 2026" |
| Outer Collection | collReF4xw.name | "Frankfurt Central Hub" |
| Outer Collection Key | collReF4xw.id | "wh-eu-west" |
| Mid Collection | collGt9dkd.carrier | "DHL Express" |
| Mid Collection Key | collGt9dkd.id | "ship-901" |
| Innermost Collection | collDkdke9.trackingNumber | "DHL-88912" |
| Innermost Collection Key | collDkdke9.fee | 120 |
Always Use collectionId in Nested Repeaters
nested collections should always use the full prefix (warehouse.id,
shipment.id). This guarantees that template refactoring or changes in JSON
payload structure will never cause accidental scope shadowing.
Summary Aggregations Across Scopes
With collectionId, you can perform mathematical aggregations across nested boundary layers:
'Compute total fees for the current shipment'
SUM(shipment.packages, 'fee')
'Display warehouse-level shipment count'
COUNT(warehouse.shipments)Next Steps
- Learn how to plot collection arrays directly into charts: Charts, Formulas & LaTeX
- Explore how to place collections into isolated physical pages: Variable Sections
Charts, Formulas & LaTeX
End-to-end guide to building analytical reports with dynamic chart visualizations, data-formula reshaping (MAP), hidden calculation layers, custom variable inputs, grouped tables, and LaTeX mathematical typesetting.
Variable Sections & Page Layouts
Configure multi-section documents with mixed paper formats, independent page margins, portrait and landscape orientations, and per-section header/footer visibility.