ECSQL Row Formats
The asynchronous ECSqlReader and synchronous ECSqlSyncReader use the same QueryRowFormat options. Set rowFormat when calling createQueryReader or withQueryReader.
Row proxies and materialized rows
Iteration and step() expose a QueryRowProxy for the current row. It supports zero-based column indexes and case-insensitive lookup using ECSQL or JavaScript property names. The proxy follows the reader's current row; materialize a row before retaining it across reader advances.
| Operation | Result |
|---|---|
row[0], row.ECInstanceId |
One value from the current row |
row.toArray() |
The current row's raw array of values in SELECT-column order |
row.toRow() |
A plain object; ECSQL property names by default, or legacy JavaScript names with the deprecated UseJsPropertyNames |
reader.toArray() |
All remaining rows, materialized according to rowFormat; returns a promise for the async reader |
row.toRow() always produces an object, including with the default index format. reader.toArray() uses the following formats for each collected row:
rowFormat |
Materialized row | Class-ID values by default |
|---|---|---|
UseECSqlPropertyIndexes (default) |
Array in SELECT-column order | Id64 strings |
UseECSqlPropertyNames |
Object keyed by ECSQL column names or aliases | Id64 strings |
UseJsPropertyNames (deprecated) |
Object keyed by legacy JavaScript names | Class names for unaliased class-ID system properties, including navigation relationship classes |
Object rows omit null and undefined values. Array rows preserve nulls before a later non-null column, but omit trailing nulls. An omitted trailing column reads as undefined by index. Allow for absent values when assigning query results to TypeScript types.
See row-format examples for code and representative output.
Property names
UseECSqlPropertyNames preserves the ECSQL column name or alias. For new code, use this format with explicit aliases and ec_classname() projections when JavaScript-friendly names and class names are required.
UseJsPropertyNames is deprecated. It lowercases the first character of ordinary property names and aliases, and maps unaliased system properties as follows. Use it only to preserve an existing result contract while migrating.
System properties when deprecated UseJsPropertyNames is used
| ECSQL property | JavaScript property | Value |
|---|---|---|
ECInstanceId |
id |
Id64 string |
ECClassId |
className |
Qualified class name |
SourceECInstanceId |
sourceId |
Id64 string |
SourceECClassId |
sourceClassName |
Qualified class name |
TargetECInstanceId |
targetId |
Id64 string |
TargetECClassId |
targetClassName |
Qualified class name |
Navigation properties use { id, relClassName } in this format. The conversion includes class-ID values as well as property keys; renaming ECClassId to className alone does not convert its value.
System properties when UseECSqlPropertyNames is used
System-property keys retain their ECSQL names, such as ECInstanceId and ECClassId. Navigation properties use { Id, RelECClassId }, with both values represented as Id64 strings. The default index format uses the same value representation, including these nested navigation objects.
Point members retain ECSQL casing in the default index format and in UseECSqlPropertyNames, producing { X, Y } or { X, Y, Z }. The deprecated UseJsPropertyNames format converts them to { x, y } or { x, y, z }.
Aliases and class names
Aliases determine the output key and can suppress automatic class-name conversion. For example, selecting ECClassId AS elementClassId preserves an ID with the default conversion options even when using JS names. The same value is exposed through index access, name access, toRow(), and toArray(). Use an explicit expression when a selected value must be a class name:
The deprecated convertClassIdsToClassNames reader option also requests class-name conversion. Use an explicit ec_classname() projection instead. The deprecated UseJsPropertyNames format already supplies the legacy system-property conversions shown above.
Property value types
| ECSQL value | JavaScript representation |
|---|---|
| Boolean | boolean |
| Blob | Uint8Array by default; a byte-count string when abbreviateBlobs is true |
| Blob with BeGuid extended type | GuidString |
| Double, Integer, Int64 | number; account for JavaScript integer precision limits |
| DateTime | ISO 8601 date-time string |
| Instance ID or Int64 with Id extended type | Id64String |
| Class-ID system property | Id64 string or qualified class name, as described above |
| Point2d | { X, Y } by default; { x, y } with deprecated UseJsPropertyNames |
| Point3d | { X, Y, Z } by default; { x, y, z } with deprecated UseJsPropertyNames |
| String | string |
| Navigation | { Id, RelECClassId } or NavigationValue, depending on format |
| Struct | Object containing the struct's members |
| Array | Array of property values |
With abbreviateBlobs: true, ordinary blobs are returned as strings such as '{"bytes":123}', describing their byte count instead of returning their contents. The option defaults to false.
Read-value support does not imply that the same value can be bound as a query parameter. See ECSQL parameter types.
Instance JSON and OPTIONS USE_JS_PROP_NAMES
The SQL option USE_JS_PROP_NAMES applies to JSON produced by the $ instance accessor:
This option controls the properties and values inside the selected JSON instance. The reader's rowFormat controls the surrounding query row. Neither option selects which connection or thread executes the query. See instance queries and ECSQL options.
Legacy statement rows
The deprecated ECSqlStatement.getRow defaults to JS-shaped rows. It also accepts ECSqlRowArg formatting options. When migrating, prefer UseECSqlPropertyNames with explicit aliases and ec_classname() projections. Use deprecated UseJsPropertyNames only when an existing caller requires the exact legacy shape. See backend migration guidance.
Last Updated: 02 October, 2026