Ledger queries

Sum Queries

A sum query returns an aggregate over the amount fields in a list of objects. As with list queries, you can add a filter to narrow the set of results that are summed.

On this page

Only actions and token groups support the sum query, because they are the only objects that contain an amount field.

Sum tokensLink to this section

Tokens represent the current state of the ledger - all amounts that have been issued, but not retired.

The sum tokens query is how you retrieve aggregate totals of the current state (e.g the balance of USD in an account).

Sum actionsLink to this section

Actions represent the historical state of the ledger - all amounts that have been issued, transferred, or retired.

The sum actions query is how you retrieve aggregate totals of the historical state (e.g total amount of USD ever issued).

Group ByLink to this section

The group-by query parameter indicates how amounts of a set of actions or token groups should be summed.

The query will break the results into groups where all values of each group-by field are identical. This is analogous to the "GROUP BY" clause in SQL.

If no group-by parameter is specified, all results will be summed to a single amount.

Data StructureLink to this section

The sum actions query returns action sum objects. The sum tokens query returns token sum objects.

In both cases, the results contain a subset of the parent object being summed (action and token group object, respectively).

The amount field is always present, but other fields are only present if they are included in the group-by parameter in the request.

For example, when summing tokens grouped by asset id and account id, the results might be:

{
  amount: 10,
  assetId: "usd",
  accountId: "alice"
},
{
  amount: 20,
  assetId: "eur",
  accountId: "bob"
}
{
  amount: 10,
  assetId: "usd",
  accountId: "alice"
},
{
  amount: 20,
  assetId: "eur",
  accountId: "bob"
}
{
  amount: 10,
  asset_id: "usd",
  account_id: "alice"
},
{
  amount: 20,
  asset_id: "eur",
  account_id: "bob"
}

Or when summing actions grouped by type and asset id, one of the results might be:

{
  amount: 10,
  type: "issue",
  assetId: "usd",
},
{
  amount: 20,
  type: "issue",
  assetId: "eur",
}
{
  amount: 10,
  type: "issue",
  assetId: "usd",
},
{
  amount: 20,
  type: "issue",
  assetId: "eur",
}
{
  amount: 10,
  type: "issue",
  asset_id: "usd",
},
{
  amount: 20,
  type: "issue",
  asset_id: "eur",
}

ExamplesLink to this section

The following examples each retrieve the first two pages of results, with 10 results per page. For details on iterating through all results, see iterating results.

Sum TokensLink to this section

Query "balances" in an accountLink to this section

To query the current "balances" of Alice's account, we sum all the tokens in that account, grouped by asset id.

TokenSum.Page page1 = new Token.SumBuilder()
  .setFilter("accountId=$1")
  .addFilterParameter("alice")
  .addGroupByField("assetId")
  .setPageSize(10)
  .getPage(ledger);
for (TokenSum balance : page1.items) {
  System.out.println("amount: " + balance.amount);
  System.out.println("asset: " + balance.assetId);
}

String cursor = page1.cursor;

TokenSum.Page page2 = new Token.SumBuilder()
  .getPage(ledger, cursor);
for (TokenSum balance : page2.items) {
  System.out.println("amount: " + balance.amount);
  System.out.println("asset: " + balance.assetId);
}
const page1 = await ledger.tokens.sum({
  filter: 'accountId=$1',
  filterParams: ['alice'],
  groupBy: ['assetId']
}).page({size: 10})

page1.items.forEach(balance => {
  console.log('amount: ', balance.amount)
  console.log('asset: ', balance.assetId)
})

const cursor = page1.cursor

const page2 = await ledger.tokens.sum().page({cursor: cursor})

page2.items.forEach(balance => {
  console.log('amount: ', balance.amount)
  console.log('asset: ', balance.assetId)
})
page1 = ledger.tokens.sum(
  filter: 'account_id=$1',
  filter_params: ['alice'],
  group_by: ['asset_id']
).page(size: 10)

page1.each do |balance|
  puts 'amount: ', balance.amount
  puts 'asset: ', balance.asset_id
end

cursor = page1.cursor

page2 = ledger.tokens.sum.page(cursor: cursor)

page2.each do |balance|
  puts 'amount: ', balance.amount
  puts 'asset: ', balance.asset_id
end

Which might output:

amount: 10
asset: usd

amount: 200
asset: acme-series-a

Query "circulation" of an assetLink to this section

If we want to know the total amount of USD in the ledger across all accounts, we sum all tokens of that asset across all accounts.

Since we are looking for a single value, we do not need to provide a group-by parameter or request a second page of results.

TokenSum.Page page1 = new Token.SumBuilder()
  .setFilter("assetId=$1")
  .addFilterParameter("usd")
  .setPageSize(10)
  .getPage(ledger);
for (TokenSum circulation : page1.items) {
  System.out.println("circulation: " + circulation.amount);
}
const page1 = await ledger.tokens.sum({
  filter: 'assetId=$1',
  filterParams: ['usd']
}).page({size: 10})

page1.items.forEach(circulation => {
  console.log('circulation: ', circulation.amount)
})
page1 = ledger.tokens.sum(
  filter: 'asset_id=$1',
  filter_params: ['usd']
).page(size: 10)

page1.each do |circulation|
  puts 'circulation: ', circulation.amount
end

Which will output:

circulation: x

Query the total amount of USD in all accounts with checking as the value for the type field in the account tags.

Since we are looking for a single value, we do not need to provide a group-by parameter or request a second page of results.

TokenSum.page page1 = new Token.SumBuilder()
  .setFilter("assetId=$1 AND accountTags.type=$2")
  .addFilterParameter("usd")
  .addFilterParameter("checking")
  .setPageSize(10)
  .getPage(ledger);
for (TokenSum balance : page1.items) {
  ...
}
const page1 = await ledger.tokens.sum({
  filter: 'assetId=$1 AND accountTags.type=$2',
  filterParams: ['usd', 'checking']
}).page({size: 10})

page1.items.forEach(balance => {
  console.log('balance: ', balance.amount)
})
page1 = ledger.tokens.sum(
  filter: 'asset_id=$1 AND account_tags.type=$2',
  filter_params: ['usd', 'checking']
).page(size: 10)

page1.each do |balance|
  puts 'balance: ', balance.amount
end

Which will output:

balance: x

Query the total balance of all USD denominated gift cards in Alice's account.

Since we are looking for a single value, we do not need to provide a group-by parameter or request a second page of results.

TokenSum.page page1 = new Token.SumBuilder()
  .setFilter("accountId=$1 AND assetTags.currency=$2 AND assetTags.type=$3")
  .addFilterParameter("alice")
  .addFilterParameter("usd")
  .addFilterParameter("giftCard")
  .setPageSize(10)
  .getPage(ledger);
for (TokenSum balance : page1.items) {
  ...
}
const page1 = await ledger.tokens.sum({
  filter: 'accountId=$1 AND assetTags.currency=$2 AND assetTags.type=$3',
  filterParams: ['alice', 'usd', 'giftCard']
}).page({size: 10})

page1.items.forEach(balance => {
  console.log('balance: ', balance.amount)
})
page1 = ledger.tokens.sum(
  filter: 'account_id=$1 AND asset_tags.currency=$2 AND asset_tags.type=$3',
  filter_params: ['alice', 'usd', 'gift_card']
).page(size: 10)

page1.each do |balance|
  puts 'balance: ', balance.amount
end

Which will output:

balance: x

Sum ActionsLink to this section

Query total amount issued of an assetLink to this section

To query the total amount of USD ever issued, you sum all the actions that issue tokens of that asset.

This is distinct from summing all the tokens of the asset, because it will include amounts that have been retired (and are therefore no longer in the ledger).

Since we are looking for a single value, we do not need to provide a group-by parameter or request a second page of results.

ActionSum.Page page1 = new Action.SumBuilder()
  .setFilter("type=$1 AND assetId=$2")
  .addFilterParameter("issue")
  .addFilterParameter("usd")
  .setPageSize(10)
  .getPage(ledger);
for (ActionSum total : page1.items) {
  System.out.println("amount: " + total.amount);
}
const page1 = await ledger.actions.sum({
  filter: 'type=$1 AND assetId=$2',
  filterParams: ['issue', 'usd']
}).page({size: 10})

page1.items.forEach(total => {
  console.log("total: ", total.amount)
})
page1 = ledger.actions.sum(
  filter: 'type=$1 AND asset_id=$2',
  filter_params: ['issue', 'usd']
).page(size: 10)

page1.each do |total|
  puts 'total: ', total.amount
end

Which will output:

total: x

Query total amount of an asset deposited into each account for a time periodLink to this section

Assuming a deposit is modeled as an issuance, to query the total amount of USD deposited into every account in the ledger today, you sum all the actions that issue usd since time t, grouped by account id.

ActionSum.Page page1 = new Action.SumBuilder()
  .setFilter("type=$1 AND assetId=$2 AND timestamp > $3")
  .addFilterParameter("issue")
  .addFilterParameter("usd")
  .addFilterParameter(t)
  .addGroupByField("destinationAccountId")
  .setPageSize(10)
  .getPage(ledger);
for (ActionSum deposit : page1.items) {
  System.out.println("amount: " + deposit.amount);
  System.out.println("account: " + deposit.destinationAccountId);
}

String cursor = page1.cursor;

ActionSum.Page page2 = new Action.SumBuilder()
  .getPage(ledger, cursor);
for (ActionSum deposit : page2.items) {
  System.out.println("amount: " + deposit.amount);
  System.out.println("account: " + deposit.destinationAccountId);
}
const page1 = await ledger.actions.sum({
  filter: 'type=$1 AND assetId=$2 AND timestamp > $3',
  filterParams: ['issue', 'usd', t],
  groupBy: ['destinationAccountId']
}).page({size: 10})

page1.items.forEach(deposit => {
  console.log("account: ", deposit.destinationAccountId)
  console.log("amount: ", deposit.amount)
})

const cursor = page1.cursor

const page2 = await ledger.actions.sum().page({cursor: cursor})

page2.items.forEach(deposit => {
  console.log("account: ", deposit.destinationAccountId)
  console.log("amount: ", deposit.amount)
})
page1 = ledger.actions.sum(
  filter: 'type=$1 AND asset_id=$2 AND timestamp > $3',
  filter_params: ['issue', 'usd', t],
  group_by: ['destination_account_id']
).page(size: 10)

page1.each do |deposit|
  puts 'account: ', deposit.destination_account_id
  puts 'amount: ', deposit.amount
end

cursor = page1.cursor

page2 = ledger.actions.sum.page(cursor: cursor)

page2.each do |deposit|
  puts 'account: ', deposit.destination_account_id
  puts 'amount: ', deposit.amount
end

Which will output:

account: alice
amount: x

account: bob
amount: y

account: carol
amount: z

...