Skip to content

Reading Data#

Concourse provides several methods for retrieving data from records. Each method is designed for a specific access pattern, and most support optional ordering, pagination, and time travel.

Selecting All Values#

The select method returns every value stored for a key (or all keys) in a record. Because Concourse fields can hold multiple values simultaneously, select returns a Set of values for each key.

Select All Keys from a Record#

1
2
// Java
Map<String, Set<Object>> data = concourse.select(1);
1
2
// CaSH
select 1

Select Specific Keys from a Record#

1
2
3
// Java
Map<String, Set<Object>> data = concourse.select(
    Lists.newArrayList("name", "age"), 1);
1
2
// CaSH
select "name", "age" from 1

Select from Multiple Records#

1
2
3
// Java
Map<Long, Map<String, Set<Object>>> data =
    concourse.select(Lists.newArrayList(1L, 2L, 3L));
1
2
// CaSH
select from [1, 2, 3]

Select with Criteria#

You can select data from all records matching a query.

1
2
3
// Java
Map<Long, Map<String, Set<Object>>> data =
    concourse.select("age > 21");
1
2
// CaSH
select from where age > 21
1
2
3
4
5
// Java - with specific keys
Map<Long, Map<String, Set<Object>>> data =
    concourse.select(
        Lists.newArrayList("name", "email"),
        "department = Engineering");

Getting the Most Recent Value#

The get method returns the single most recently added value for a key in a record. Use get when you only need the current value and the field is expected to contain a single value.

Get a Single Value#

1
2
// Java
Object name = concourse.get("name", 1);
1
2
// CaSH
get "name" from 1

Get Multiple Keys from a Record#

1
2
3
// Java
Map<String, Object> data = concourse.get(
    Lists.newArrayList("name", "email"), 1);

Get a Key from Multiple Records#

1
2
3
// Java
Map<Long, Object> names = concourse.get("name",
    Lists.newArrayList(1L, 2L, 3L));

Get with Criteria#

1
2
3
// Java
Map<Long, Map<String, Object>> data =
    concourse.get("age > 21");
1
2
// CaSH
get from where age > 21

Select vs Get#

select get
Returns All values (Set) Most recent value
Use when Field has multiple values Field has one value
Multi-valued fields Returns complete set Returns latest only

Browsing Values Across a Key#

The browse method returns an inverted view of a key’s data, mapping each distinct value to the set of records that contain it. This is useful for understanding the distribution of values across records.

1
2
3
// Java
Map<Object, Set<Long>> index = concourse.browse("color");
// e.g., {"red" -> [1, 4, 7], "blue" -> [2, 3], ...}
1
2
// CaSH
browse "color"

Browse Multiple Keys#

1
2
3
4
// Java
Map<String, Map<Object, Set<Long>>> index =
    concourse.browse(
        Lists.newArrayList("color", "size"));

Historical Browse#

1
2
3
// Java
Map<Object, Set<Long>> index = concourse.browse(
    "color", Timestamp.fromString("2 days ago"));

Describing Records#

The describe method returns the set of keys that currently have at least one value in a record. Use this to discover which fields exist in a record without retrieving the actual data.

1
2
// Java
Set<String> keys = concourse.describe(1);
1
2
// CaSH
describe 1

Describe All Keys in the Database#

Call describe with no arguments to get every key that has at least one value in the entire database.

1
2
// Java
Set<String> allKeys = concourse.describe();

Describe Multiple Records#

1
2
3
// Java
Map<Long, Set<String>> keysByRecord =
    concourse.describe(Lists.newArrayList(1L, 2L, 3L));

Record Inventory#

The inventory method returns the IDs of all records that have current or historical data.

1
2
// Java
Set<Long> allRecords = concourse.inventory();
1
2
// CaSH
inventory

Checking Record Existence#

The holds method checks whether a record currently contains any data. This is faster than calling describe when you only need to know if a record exists.

1
2
// Java
boolean exists = concourse.holds(1);
1
2
// CaSH
holds 1

Check Multiple Records#

1
2
3
// Java
Map<Long, Boolean> existence = concourse.holds(
    Lists.newArrayList(1L, 2L, 3L));

Verifying Values#

The verify method checks whether a specific value is currently stored for a key in a record.

1
2
3
// Java
boolean isStored = concourse.verify("name",
    "Jeff Nelson", 1);
1
2
// CaSH
verify "name", "Jeff Nelson", 1

Historical Verification#

1
2
3
4
// Java
boolean wasStored = concourse.verify("name",
    "Jeff Nelson", 1,
    Timestamp.fromString("last week"));

Exporting as JSON#

The jsonify method atomically serializes one or more records as a JSON string. Optionally include the record identifier in the output.

1
2
3
// Java
String json = concourse.jsonify(1);
String jsonWithId = concourse.jsonify(1, true);
1
2
// CaSH
jsonify 1

Jsonify Multiple Records#

1
2
3
// Java
String json = concourse.jsonify(
    Lists.newArrayList(1L, 2L, 3L), true);

The $id$ Intrinsic Key#

Every record in Concourse has an implicit $id$ key that maps to the record’s unique identifier. You can use $id$ in read operations to include the record ID in results.

1
2
3
// Java
Map<String, Set<Object>> data = concourse.select(
    Lists.newArrayList("$id$", "name", "email"), 1);

The $id$ key is especially useful with aggregations to count matching records:

1
2
3
// Java
long count = concourse.calculate().count(
    "$id$", "department = Engineering");

Ordering Results#

Multi-record reads can be sorted by specifying an Order. See Ordering Results for full documentation.

1
2
3
4
// Java
Map<Long, Map<String, Set<Object>>> data =
    concourse.select("age > 21",
        Order.by("name").ascending());

Pagination#

Large result sets can be paginated using a Page. See Pagination for full documentation.

1
2
3
4
// Java
Map<Long, Map<String, Set<Object>>> data =
    concourse.select("age > 21",
        Page.skipLimit(0, 10));

Navigation keys use dot-separated paths to traverse links and read data from linked records. See Graph for full documentation.

1
2
3
4
5
// Java
// Read the "name" of the record linked via "employer"
Map<Long, Set<Object>> names =
    concourse.navigate("employer.name",
        Lists.newArrayList(1L, 2L));

Temporal Reads#

All read methods accept an optional Timestamp parameter to retrieve historical data. See Time Travel for full documentation.

1
2
3
// Java
Object oldName = concourse.get("name", 1,
    Timestamp.fromString("January 1, 2025"));