Relational Data
Reference records across collections and fetch them in a single query using populate.
How it works
Koolbase doesn't enforce foreign keys — but you can store the ID of a related record as a field in your data. For example, a posts record might have an author_id field containing the ID of a record in the users collection.
When querying, pass a populate list to resolve those references server-side. The API fetches the related records in a single batched query and injects them inline — no extra round trips from your app.
The populated field is injected with the _id suffix removed. So author_id becomes author, and category_id becomes category.
Storing references
Store the related record's ID as a field in your data. Use the _id suffix by convention — it makes populate work automatically.
// Insert a post with a reference to the author
await Koolbase.db.collection('posts').insert({
'title': 'Getting started with Koolbase',
'body': 'Koolbase makes Flutter backends easy...',
'author_id': 'user-uuid-here', // reference to a users record
'category_id': 'category-uuid-here', // reference to a categories record
});Querying with populate
Use .populate() on the query builder. Pass a list of strings in the format "field_name:collection_name".
final result = await Koolbase.db
.collection('posts')
.populate(['author_id:users', 'category_id:categories'])
.get();
for (final post in result.records) {
final title = post.data['title'] as String;
// Populated author record
final author = post.data['author'] as Map<String, dynamic>?;
final authorName = author?['data']['name'] as String?;
// Populated category record
final category = post.data['category'] as Map<String, dynamic>?;
final categoryName = category?['data']['name'] as String?;
print('$title by $authorName in $categoryName');
}Populate format
field_name:collection_name. The field_name is the key in your record's data that holds the referenced ID. The collection_name is the collection to look up.Response shape
The original reference field is preserved and the populated record is injected alongside it:
{
"id": "post-uuid",
"data": {
"title": "Getting started with Koolbase",
"author_id": "user-uuid",
"author": {
"id": "user-uuid",
"data": {
"name": "Kennedy Owusu",
"email": "kennedy@example.com"
},
"created_at": "2026-03-25T00:00:00Z",
"updated_at": "2026-03-25T00:00:00Z"
},
"category_id": "category-uuid",
"category": {
"id": "category-uuid",
"data": { "name": "Engineering" },
"created_at": "2026-03-25T00:00:00Z",
"updated_at": "2026-03-25T00:00:00Z"
}
},
"created_at": "2026-03-25T00:00:00Z",
"updated_at": "2026-03-25T00:00:00Z"
}Combining with filters and ordering
.populate() works alongside all other query methods:
final result = await Koolbase.db
.collection('posts')
.where('published', isEqualTo: true)
.orderBy('created_at', descending: true)
.limit(10)
.populate(['author_id:users'])
.get();