Getting a Collection of Instances
Sometimes you need every instance of a read model at once: a small report, an integrity check, a back-office export, or a diagnostic script. Chronicle answers this the same way it answers a single-instance read — from the materialized store when the read model has one, and by replaying events when it does not.
Either way the whole result set comes back in one call, so this is not the tool for hot list views or large data sets. Reach for materialized paging when the caller needs a window rather than everything.
Read all instances
Section titled “Read all instances”var accounts = await eventStore.ReadModels.GetInstances<Account>();
foreach (var account in accounts){ Console.WriteLine($"{account.Name}: {account.Balance:C}");}import io.cratis.chronicle.IEventStoreimport io.cratis.chronicle.readModels.ReadModel
@ReadModeldata class GettingCollectionAccount(val name: String = "", val balance: Double = 0.0)
suspend fun printAllAccounts(store: IEventStore) { val accounts = store.readModels.getInstances(GettingCollectionAccount::class) accounts.forEach { println("${it.name}: ${it.balance}") }}import io.cratis.chronicle.EventStore;import io.cratis.chronicle.readModels.ReadModel;
import java.util.List;
import io.cratis.chronicle.java.ReadModelsJavaBridge;
@ReadModelclass GettingCollectionAccount { private String name = ""; private double balance = 0;
public String getName() { return name; } public void setName(String name) { this.name = name; }
public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; }}
class ReadModelsGettingCollectionInstancesBasic { void printAllAccounts(EventStore store) { List<GettingCollectionAccount> accounts = ReadModelsJavaBridge.getInstances(store.getReadModels(), GettingCollectionAccount.class); accounts.forEach(account -> System.out.println(account.getName() + ": " + account.getBalance())); }}alias MyApp.ReadModels.Account
{:ok, accounts} = Chronicle.ReadModels.get_instances(Account)
Enum.each(accounts, fn account -> IO.puts("#{account.name}: #{account.balance}")end)const accounts = await store.readModels.getInstances(Account);
for (const account of accounts) { console.log(`${account.name}: ${account.balance}`);}Kotlin currently exposes single-instance read-model lookup only, so collection reads are not shown for that client.
For a materialized read model the kernel pages through the sink until it has read every stored instance, releases compliance-protected values, and returns them. For a passive read model it replays the events that feed the read model and returns the state that falls out, which is strongly consistent and proportional to the length of the history.
Filter in memory
Section titled “Filter in memory”The read returns every instance. Apply language-native filtering afterwards, and keep that in-memory cost in mind.
var accounts = await eventStore.ReadModels.GetInstances<Account>();
var highValueAccounts = accounts .Where(account => account.Balance > threshold) .OrderByDescending(account => account.Balance) .ToList();
Console.WriteLine($"Found {highValueAccounts.Count} high-value accounts.");import io.cratis.chronicle.IEventStoreimport io.cratis.chronicle.readModels.ReadModel
@ReadModeldata class GettingCollectionFilteringAccount(val name: String = "", val balance: Double = 0.0)
/** * The read returns every instance; apply language-native filtering afterwards. */suspend fun highValueAccounts(store: IEventStore, threshold: Double): List<GettingCollectionFilteringAccount> = store.readModels.getInstances(GettingCollectionFilteringAccount::class) .filter { it.balance > threshold } .sortedByDescending { it.balance }import io.cratis.chronicle.EventStore;import io.cratis.chronicle.readModels.ReadModel;
import java.util.Comparator;import java.util.List;import java.util.stream.Collectors;
import io.cratis.chronicle.java.ReadModelsJavaBridge;
@ReadModelclass GettingCollectionFilteringAccount { private String name = ""; private double balance = 0;
public String getName() { return name; } public void setName(String name) { this.name = name; }
public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; }}
class ReadModelsGettingCollectionInstancesFiltering { // The read returns every instance; apply language-native filtering afterwards. List<GettingCollectionFilteringAccount> highValueAccounts(EventStore store, double threshold) { List<GettingCollectionFilteringAccount> accounts = ReadModelsJavaBridge.getInstances(store.getReadModels(), GettingCollectionFilteringAccount.class); return accounts.stream() .filter(account -> account.getBalance() > threshold) .sorted(Comparator.comparingDouble(GettingCollectionFilteringAccount::getBalance).reversed()) .collect(Collectors.toList()); }}alias MyApp.ReadModels.Account
{:ok, accounts} = Chronicle.ReadModels.get_instances(Account)
high_value_accounts = accounts |> Enum.filter(&(&1.balance > threshold)) |> Enum.sort_by(& &1.balance, :desc)
IO.inspect(high_value_accounts, label: "High-value accounts")const accounts = await store.readModels.getInstances(Account);
const highValueAccounts = accounts .filter((account) => account.balance > threshold) .sort((left, right) => right.balance - left.balance);For large result sets, page the materialized read model or use a product-specific query model instead of reading everything and filtering afterward.
Limit the replay
Section titled “Limit the replay”You can cap the number of events Chronicle processes. Because a cap only means something to a replay, passing one always replays — even for a materialized read model.
var orders = await eventStore.ReadModels.GetInstances<Order>(eventCount: 1_000);
Console.WriteLine($"Replayed {orders.Count()} orders from the capped history.");import io.cratis.chronicle.IEventStoreimport io.cratis.chronicle.readModels.ReadModel
@ReadModeldata class EventCountOrder(val status: String = "", val total: Double = 0.0)
/** * Caps the replay to the first 1,000 events - faster, but can return incomplete state if the * cap cuts off events that matter. */suspend fun replayCappedOrders(store: IEventStore): List<EventCountOrder> = store.readModels.getInstances(EventCountOrder::class, eventCount = 1_000)import io.cratis.chronicle.IEventStore;import io.cratis.chronicle.java.ReadModelsJavaBridge;import io.cratis.chronicle.readModels.ReadModel;
import java.util.List;
@ReadModelrecord EventCountOrder(String status, double total) {}
class EventCountOrders { /** * Caps the replay to the first 1,000 events - faster, but can return incomplete state if the * cap cuts off events that matter. */ static List<EventCountOrder> replayCappedOrders(IEventStore store) { return ReadModelsJavaBridge.getInstances(store.getReadModels(), EventCountOrder.class, 1_000L); }}alias MyApp.ReadModels.Order
{:ok, orders} = Chronicle.ReadModels.get_instances( Order, event_count: 1_000 )
IO.puts("Replayed #{length(orders)} orders from the capped history.")const orders = await store.readModels.getInstances(Order, 1000n);
console.log(`Replayed ${orders.length} orders from the capped history.`);This can make diagnostics faster, but it can also return incomplete state if the cap cuts off events that matter. Use an event-count cap for historical analysis, back-testing, or bounded diagnostics. Do not use it when the reader expects the current truth.
When to use this
Section titled “When to use this”Read the whole collection when:
- The read model population is small.
- You are running an administrative or diagnostic task.
- You are validating data derived from the event log.
Prefer paging or a database-native read when:
- The page is user-facing and called frequently.
- You need server-side filtering, sorting, or paging.
- The read model has many instances.
Related topics
Section titled “Related topics”- Getting a Single Instance - Read one read model instance by key
- Getting Snapshots - Inspect historical state for one instance
- Watching Read Models - React to read model changes
- Materialized Read Models - Read sink-stored read models with paging