Node.js-Client (Neo)
Installation Um den DuckDB-Node.js-Client zu verwenden, besuchen Sie die Node.js-Installationsseite.
Die aktuellste stabile Version des DuckDB-Node.js-Clients (Neo) ist 1.5.5.
Eine API zur Nutzung von DuckDB in Node.js.
Das primäre Paket @duckdb/node-api ist eine High-Level-API für Anwendungen. Es hängt von Low-Level-Bindings ab, die sich eng an die C-API von DuckDB halten und separat als @duckdb/node-bindings verfügbar sind.
Roadmap
Einige Funktionen sind noch nicht vollständig:
- Binden und Anhängen der Datentypen MAP und UNION
- Anhängen von Standardwerten zeilenweise
- Benutzerdefinierte Typen und Funktionen
- Profiling-Informationen
- Tabellenbeschreibung
- APIs für Arrow
Die aktuellste Roadmap finden Sie in der Issues-Liste auf GitHub.
Plattformen
Der Node.js-Client (Neo) unterstützt die folgenden Plattformen:
linux_amd64linux_arm64osx_amd64osx_arm64windows_amd64
Die Plattform windows_arm64 wird derzeit nicht unterstützt.
Beispiele
Grundlegende Informationen abrufen
import duckdb from '@duckdb/node-api';
console.log(duckdb.version());
console.log(duckdb.configurationOptionDescriptions());Verbinden
import { DuckDBConnection } from '@duckdb/node-api';
const connection = await DuckDBConnection.create();Dies verwendet die Standardinstanz. Für fortgeschrittene Nutzung können Sie Instanzen explizit erstellen.
Instanz erstellen
import { DuckDBInstance } from '@duckdb/node-api';Mit einer In-Memory-Datenbank erstellen:
const instance = await DuckDBInstance.create(':memory:');Entspricht dem Obigen:
const instance = await DuckDBInstance.create();Aus einer Datenbankdatei lesen und in sie schreiben; die Datei wird bei Bedarf erstellt:
const instance = await DuckDBInstance.create('my_duckdb.db');Konfigurationsoptionen setzen:
const instance = await DuckDBInstance.create('my_duckdb.db', { threads: '4'});Instanz-Cache
Mehrere Instanzen im selben Prozess sollten nicht dieselbe Datenbank anhängen.
Um das zu verhindern, kann ein Instanz-Cache verwendet werden:
const instance = await DuckDBInstance.fromCache('my_duckdb.db');Dies verwendet den Standard-Instanz-Cache. Für fortgeschrittene Nutzung können Sie Instanz-Caches explizit erstellen:
import { DuckDBInstanceCache } from '@duckdb/node-api';
const cache = new DuckDBInstanceCache();const instance = await cache.getOrCreateInstance('my_duckdb.db');Mit einer Instanz verbinden
const connection = await instance.connect();Trennen
Verbindungen werden automatisch getrennt, sobald ihre Referenz nicht mehr gehalten wird; Sie können aber auch explizit trennen, wann Sie möchten:
connection.disconnectSync();oder gleichwertig:
connection.closeSync();SQL ausführen
const result = await connection.run('from test_all_types()');SQL parametrisieren
const prepared = await connection.prepare('select $1, $2, $3');prepared.bindVarchar(1, 'duck');prepared.bindInteger(2, 42);prepared.bindList(3, listValue([10, 11, 12]), LIST(INTEGER));const result = await prepared.run();oder:
const prepared = await connection.prepare('select $a, $b, $c');prepared.bind({ 'a': 'duck', 'b': 42, 'c': listValue([10, 11, 12]),}, { 'a': VARCHAR, 'b': INTEGER, 'c': LIST(INTEGER),});const result = await prepared.run();oder sogar:
const result = await connection.run('select $a, $b, $c', { 'a': 'duck', 'b': 42, 'c': listValue([10, 11, 12]),}, { 'a': VARCHAR, 'b': INTEGER, 'c': LIST(INTEGER),});Nicht angegebene Typen werden erschlossen:
const result = await connection.run('select $a, $b, $c', { 'a': 'duck', 'b': 42, 'c': listValue([10, 11, 12]),});Werte angeben
Werte vieler Datentypen werden durch eines der JS-Primitive
boolean, number, bigint oder string dargestellt.
Außerdem kann jeder Typ null-Werte haben.
Werte einiger Datentypen müssen mit speziellen Funktionen erzeugt werden. Das sind:
| Typ | Funktion |
|---|---|
ARRAY |
arrayValue |
BIT |
bitValue |
BLOB |
blobValue |
DATE |
dateValue |
DECIMAL |
decimalValue |
INTERVAL |
intervalValue |
LIST |
listValue |
MAP |
mapValue |
STRUCT |
structValue |
TIME |
timeValue |
TIMETZ |
timeTZValue |
TIMESTAMP |
timestampValue |
TIMESTAMPTZ |
timestampTZValue |
TIMESTAMP_S |
timestampSecondsValue |
TIMESTAMP_MS |
timestampMillisValue |
TIMESTAMP_NS |
timestampNanosValue |
UNION |
unionValue |
UUID |
uuidValue |
Ergebnisse streamen
Streaming-Ergebnisse werden verzögert ausgewertet, wenn Zeilen gelesen werden.
const result = await connection.stream('from range(10_000)');Metadaten des Ergebnisses prüfen
Spaltennamen und -typen abrufen:
const columnNames = result.columnNames();const columnTypes = result.columnTypes();Ergebnisdaten lesen
Ausführen und alle Daten lesen:
const reader = await connection.runAndReadAll('from test_all_types()');const rows = reader.getRows();// OR: const columns = reader.getColumns();Streamen und bis zu (mindestens) einer bestimmten Anzahl von Zeilen lesen:
const reader = await connection.streamAndReadUntil( 'from range(5000)', 1000);const rows = reader.getRows();// rows.length === 2048. (Rows are read in chunks of 2048.)Zeilen schrittweise lesen:
const reader = await connection.streamAndRead('from range(5000)');reader.readUntil(2000);// reader.currentRowCount === 2048 (Rows are read in chunks of 2048.)// reader.done === falsereader.readUntil(4000);// reader.currentRowCount === 4096// reader.done === falsereader.readUntil(6000);// reader.currentRowCount === 5000// reader.done === trueErgebnisdaten abrufen
Ergebnisdaten können in verschiedenen Formen abgerufen werden:
const reader = await connection.runAndReadAll( 'from range(3) select range::int as i, 10 + i as n');
const rows = reader.getRows();// [ [0, 10], [1, 11], [2, 12] ]
const rowObjects = reader.getRowObjects();// [ { i: 0, n: 10 }, { i: 1, n: 11 }, { i: 2, n: 12 } ]
const columns = reader.getColumns();// [ [0, 1, 2], [10, 11, 12] ]
const columnsObject = reader.getColumnsObject();// { i: [0, 1, 2], n: [10, 11, 12] }Ergebnisdaten konvertieren
Standardmäßig werden Datenwerte, die nicht als JS-Built-ins dargestellt werden können,
als spezialisierte JS-Objekte zurückgegeben; siehe unten Datenwerte prüfen.
Um Daten in einer anderen Form abzurufen, etwa als JS-Built-ins oder als Werte, die
verlustfrei nach JSON serialisiert werden können, verwenden Sie die Formen JS oder Json der
obigen Methoden für Ergebnisdaten.
Eigene Converter können ebenfalls übergeben werden. Siehe die Implementierungen von JSDuckDBValueConverter und JsonDuckDBValueConverters, um zu sehen, wie das geht.
Beispiele (mit den Json-Formen):
const reader = await connection.runAndReadAll( 'from test_all_types() select bigint, date, interval limit 2');
const rows = reader.getRowsJson();// [// [// "-9223372036854775808",// "5877642-06-25 (BC)",// { "months": 0, "days": 0, "micros": "0" }// ],// [// "9223372036854775807",// "5881580-07-10",// { "months": 999, "days": 999, "micros": "999999999" }// ]// ]
const rowObjects = reader.getRowObjectsJson();// [// {// "bigint": "-9223372036854775808",// "date": "5877642-06-25 (BC)",// "interval": { "months": 0, "days": 0, "micros": "0" }// },// {// "bigint": "9223372036854775807",// "date": "5881580-07-10",// "interval": { "months": 999, "days": 999, "micros": "999999999" }// }// ]
const columns = reader.getColumnsJson();// [// [ "-9223372036854775808", "9223372036854775807" ],// [ "5877642-06-25 (BC)", "5881580-07-10" ],// [// { "months": 0, "days": 0, "micros": "0" },// { "months": 999, "days": 999, "micros": "999999999" }// ]// ]
const columnsObject = reader.getColumnsObjectJson();// {// "bigint": [ "-9223372036854775808", "9223372036854775807" ],// "date": [ "5877642-06-25 (BC)", "5881580-07-10" ],// "interval": [// { "months": 0, "days": 0, "micros": "0" },// { "months": 999, "days": 999, "micros": "999999999" }// ]// }Diese Methoden behandeln auch verschachtelte Typen:
const reader = await connection.runAndReadAll( 'from test_all_types() select int_array, struct, map, "union" limit 2');
const rows = reader.getRowsJson();// [// [// [],// { "a": null, "b": null },// [],// { "tag": "name", "value": "Frank" }// ],// [// [ 42, 999, null, null, -42],// { "a": 42, "b": "🦆🦆🦆🦆🦆🦆" },// [// { "key": "key1", "value": "🦆🦆🦆🦆🦆🦆" },// { "key": "key2", "value": "goose" }// ],// { "tag": "age", "value": 5 }// ]// ]
const rowObjects = reader.getRowObjectsJson();// [// {// "int_array": [],// "struct": { "a": null, "b": null },// "map": [],// "union": { "tag": "name", "value": "Frank" }// },// {// "int_array": [ 42, 999, null, null, -42 ],// "struct": { "a": 42, "b": "🦆🦆🦆🦆🦆🦆" },// "map": [// { "key": "key1", "value": "🦆🦆🦆🦆🦆🦆" },// { "key": "key2", "value": "goose" }// ],// "union": { "tag": "age", "value": 5 }// }// ]
const columns = reader.getColumnsJson();// [// [// [],// [42, 999, null, null, -42]// ],// [// { "a": null, "b": null },// { "a": 42, "b": "🦆🦆🦆🦆🦆🦆" }// ],// [// [],// [// { "key": "key1", "value": "🦆🦆🦆🦆🦆🦆" },// { "key": "key2", "value": "goose"}// ]// ],// [// { "tag": "name", "value": "Frank" },// { "tag": "age", "value": 5 }// ]// ]
const columnsObject = reader.getColumnsObjectJson();// {// "int_array": [// [],// [42, 999, null, null, -42]// ],// "struct": [// { "a": null, "b": null },// { "a": 42, "b": "🦆🦆🦆🦆🦆🦆" }// ],// "map": [// [],// [// { "key": "key1", "value": "🦆🦆🦆🦆🦆🦆" },// { "key": "key2", "value": "goose" }// ]// ],// "union": [// { "tag": "name", "value": "Frank" },// { "tag": "age", "value": 5 }// ]// }Spaltennamen und -typen können ebenfalls nach JSON serialisiert werden:
const columnNamesAndTypes = reader.columnNamesAndTypesJson();// {// "columnNames": [// "int_array",// "struct",// "map",// "union"// ],// "columnTypes": [// {// "typeId": 24,// "valueType": {// "typeId": 4// }// },// {// "typeId": 25,// "entryNames": [// "a",// "b"// ],// "entryTypes": [// {// "typeId": 4// },// {// "typeId": 17// }// ]// },// {// "typeId": 26,// "keyType": {// "typeId": 17// },// "valueType": {// "typeId": 17// }// },// {// "typeId": 28,// "memberTags": [// "name",// "age"// ],// "memberTypes": [// {// "typeId": 17// },// {// "typeId": 3// }// ]// }// ]// }
const columnNameAndTypeObjects = reader.columnNameAndTypeObjectsJson();// [// {// "columnName": "int_array",// "columnType": {// "typeId": 24,// "valueType": {// "typeId": 4// }// }// },// {// "columnName": "struct",// "columnType": {// "typeId": 25,// "entryNames": [// "a",// "b"// ],// "entryTypes": [// {// "typeId": 4// },// {// "typeId": 17// }// ]// }// },// {// "columnName": "map",// "columnType": {// "typeId": 26,// "keyType": {// "typeId": 17// },// "valueType": {// "typeId": 17// }// }// },// {// "columnName": "union",// "columnType": {// "typeId": 28,// "memberTags": [// "name",// "age"// ],// "memberTypes": [// {// "typeId": 17// },// {// "typeId": 3// }// ]// }// }// ]Chunks abrufen
Alle Chunks abrufen:
const chunks = await result.fetchAllChunks();Jeweils einen Chunk abrufen:
const chunks = [];while (true) { const chunk = await result.fetchChunk(); // Last chunk will have zero rows. if (chunk.rowCount === 0) { break; } chunks.push(chunk);}Bei materialisierten (nicht streamenden) Ergebnissen können Chunks per Index gelesen werden:
const rowCount = result.rowCount;const chunkCount = result.chunkCount;for (let i = 0; i < chunkCount; i++) { const chunk = result.getChunk(i); // ...}Chunk-Daten abrufen:
const rows = chunk.getRows();
const rowObjects = chunk.getRowObjects(result.deduplicatedColumnNames());
const columns = chunk.getColumns();
const columnsObject = chunk.getColumnsObject(result.deduplicatedColumnNames());Chunk-Daten abrufen (jeweils ein Wert)
const columns = [];const columnCount = chunk.columnCount;for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) { const columnValues = []; const columnVector = chunk.getColumnVector(columnIndex); const itemCount = columnVector.itemCount; for (let itemIndex = 0; itemIndex < itemCount; itemIndex++) { const value = columnVector.getItem(itemIndex); columnValues.push(value); } columns.push(columnValues);}Datentypen prüfen
import { DuckDBTypeId } from '@duckdb/node-api';
if (columnType.typeId === DuckDBTypeId.ARRAY) { const arrayValueType = columnType.valueType; const arrayLength = columnType.length;}
if (columnType.typeId === DuckDBTypeId.DECIMAL) { const decimalWidth = columnType.width; const decimalScale = columnType.scale;}
if (columnType.typeId === DuckDBTypeId.ENUM) { const enumValues = columnType.values;}
if (columnType.typeId === DuckDBTypeId.LIST) { const listValueType = columnType.valueType;}
if (columnType.typeId === DuckDBTypeId.MAP) { const mapKeyType = columnType.keyType; const mapValueType = columnType.valueType;}
if (columnType.typeId === DuckDBTypeId.STRUCT) { const structEntryNames = columnType.names; const structEntryTypes = columnType.valueTypes;}
if (columnType.typeId === DuckDBTypeId.UNION) { const unionMemberTags = columnType.memberTags; const unionMemberTypes = columnType.memberTypes;}
// For the JSON type (https://duckdb.org/docs/current/data/json/json_type)if (columnType.alias === 'JSON') { const json = JSON.parse(columnValue);}Jeder Typ implementiert toString. Das Ergebnis ist sowohl menschenlesbar als auch von DuckDB in einem geeigneten Ausdruck lesbar.
const typeString = columnType.toString();Datenwerte prüfen
import { DuckDBTypeId } from '@duckdb/node-api';
if (columnType.typeId === DuckDBTypeId.ARRAY) { const arrayItems = columnValue.items; // array of values const arrayString = columnValue.toString();}
if (columnType.typeId === DuckDBTypeId.BIT) { const bools = columnValue.toBools(); // array of booleans const bits = columnValue.toBits(); // array of 0s and 1s const bitString = columnValue.toString(); // string of '0's and '1's}
if (columnType.typeId === DuckDBTypeId.BLOB) { const blobBytes = columnValue.bytes; // Uint8Array const blobString = columnValue.toString();}
if (columnType.typeId === DuckDBTypeId.DATE) { const dateDays = columnValue.days; const dateString = columnValue.toString(); const { year, month, day } = columnValue.toParts();}
if (columnType.typeId === DuckDBTypeId.DECIMAL) { const decimalWidth = columnValue.width; const decimalScale = columnValue.scale; // Scaled-up value. Represented number is value/(10^scale). const decimalValue = columnValue.value; // bigint const decimalString = columnValue.toString(); const decimalDouble = columnValue.toDouble();}
if (columnType.typeId === DuckDBTypeId.INTERVAL) { const intervalMonths = columnValue.months; const intervalDays = columnValue.days; const intervalMicros = columnValue.micros; // bigint const intervalString = columnValue.toString();}
if (columnType.typeId === DuckDBTypeId.LIST) { const listItems = columnValue.items; // array of values const listString = columnValue.toString();}
if (columnType.typeId === DuckDBTypeId.MAP) { const mapEntries = columnValue.entries; // array of { key, value } const mapString = columnValue.toString();}
if (columnType.typeId === DuckDBTypeId.STRUCT) { // { name1: value1, name2: value2, ... } const structEntries = columnValue.entries; const structString = columnValue.toString();}
if (columnType.typeId === DuckDBTypeId.TIMESTAMP_MS) { const timestampMillis = columnValue.milliseconds; // bigint const timestampMillisString = columnValue.toString();}
if (columnType.typeId === DuckDBTypeId.TIMESTAMP_NS) { const timestampNanos = columnValue.nanoseconds; // bigint const timestampNanosString = columnValue.toString();}
if (columnType.typeId === DuckDBTypeId.TIMESTAMP_S) { const timestampSecs = columnValue.seconds; // bigint const timestampSecsString = columnValue.toString();}
if (columnType.typeId === DuckDBTypeId.TIMESTAMP_TZ) { const timestampTZMicros = columnValue.micros; // bigint const timestampTZString = columnValue.toString(); const { date: { year, month, day }, time: { hour, min, sec, micros }, } = columnValue.toParts();}
if (columnType.typeId === DuckDBTypeId.TIMESTAMP) { const timestampMicros = columnValue.micros; // bigint const timestampString = columnValue.toString(); const { date: { year, month, day }, time: { hour, min, sec, micros }, } = columnValue.toParts();}
if (columnType.typeId === DuckDBTypeId.TIME_TZ) { const timeTZMicros = columnValue.micros; // bigint const timeTZOffset = columnValue.offset; const timeTZString = columnValue.toString(); const { time: { hour, min, sec, micros }, offset, } = columnValue.toParts();}
if (columnType.typeId === DuckDBTypeId.TIME) { const timeMicros = columnValue.micros; // bigint const timeString = columnValue.toString(); const { hour, min, sec, micros } = columnValue.toParts();}
if (columnType.typeId === DuckDBTypeId.UNION) { const unionTag = columnValue.tag; const unionValue = columnValue.value; const unionValueString = columnValue.toString();}
if (columnType.typeId === DuckDBTypeId.UUID) { const uuidHugeint = columnValue.hugeint; // bigint const uuidString = columnValue.toString();}
// other possible values are: null, boolean, number, bigint, or stringZeitzonen anzeigen
Die Umwandlung eines TIMESTAMP_TZ-Werts in einen String hängt von einem Zeitzonen-Offset ab. Standardmäßig ist das der Offset der lokalen Zeitzone beim Start des Node-Prozesses.
Um ihn zu ändern, setzen Sie die Eigenschaft timezoneOffsetInMinutes
von DuckDBTimestampTZValue:
DuckDBTimestampTZValue.timezoneOffsetInMinutes = -8 * 60;const pst = DuckDBTimestampTZValue.Epoch.toString();// 1969-12-31 16:00:00-08
DuckDBTimestampTZValue.timezoneOffsetInMinutes = +1 * 60;const cet = DuckDBTimestampTZValue.Epoch.toString();// 1970-01-01 01:00:00+01Beachten Sie, dass der für diese String-Konvertierung verwendete Zeitzonen-Offset
sich von der Einstellung TimeZone von DuckDB unterscheidet.
Das Folgende setzt diesen Offset so, dass er der Einstellung TimeZone von DuckDB entspricht:
const reader = await connection.runAndReadAll( `select (timezone(current_timestamp) / 60)::int`);DuckDBTimestampTZValue.timezoneOffsetInMinutes = reader.getColumns()[0][0];An Tabelle anhängen
await connection.run( `create or replace table target_table(i integer, v varchar)`);
const appender = await connection.createAppender('target_table');
appender.appendInteger(42);appender.appendVarchar('duck');appender.endRow();
appender.appendInteger(123);appender.appendVarchar('mallard');appender.endRow();
appender.flushSync();
appender.appendInteger(17);appender.appendVarchar('goose');appender.endRow();
appender.closeSync(); // also flushesDaten-Chunk anhängen
await connection.run( `create or replace table target_table(i integer, v varchar)`);
const appender = await connection.createAppender('target_table');
const chunk = DuckDBDataChunk.create([INTEGER, VARCHAR]);chunk.setColumns([ [42, 123, 17], ['duck', 'mallard', 'goose'],]);// OR:// chunk.setRows([// [42, 'duck'],// [123, 'mallard'],// [17, 'goose'],// ]);
appender.appendDataChunk(chunk);appender.flushSync();Siehe oben unter „Werte angeben“, wie Werte an den Appender übergeben werden.
Anweisungen extrahieren
const extractedStatements = await connection.extractStatements(` create or replace table numbers as from range(?); from numbers where range < ?; drop table numbers;`);const parameterValues = [10, 7];const statementCount = extractedStatements.count;for (let stmtIndex = 0; stmtIndex < statementCount; stmtIndex++) { const prepared = await extractedStatements.prepare(stmtIndex); let parameterCount = prepared.parameterCount; for (let paramIndex = 1; paramIndex <= parameterCount; paramIndex++) { prepared.bindInteger(paramIndex, parameterValues.shift()); } const result = await prepared.run(); // ...}Auswertung von Aufgaben steuern
import { DuckDBPendingResultState } from '@duckdb/node-api';
async function sleep(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); });}
const prepared = await connection.prepare('from range(10_000_000)');const pending = prepared.start();while (pending.runTask() !== DuckDBPendingResultState.RESULT_READY) { console.log('not ready'); await sleep(1);}console.log('ready');const result = await pending.getResult();// ...Möglichkeiten, SQL auszuführen
// Run to completion but don't yet retrieve any rows.// Optionally take values to bind to SQL parameters,// and (optionally) types of those parameters,// either as an array (for positional parameters),// or an object keyed by parameter name.const result = await connection.run(sql);const result = await connection.run(sql, values);const result = await connection.run(sql, values, types);
// Run to completion but don't yet retrieve any rows.// Wrap in a DuckDBDataReader for convenient data retrieval.const reader = await connection.runAndRead(sql);const reader = await connection.runAndRead(sql, values);const reader = await connection.runAndRead(sql, values, types);
// Run to completion, wrap in a reader, and read all rows.const reader = await connection.runAndReadAll(sql);const reader = await connection.runAndReadAll(sql, values);const reader = await connection.runAndReadAll(sql, values, types);
// Run to completion, wrap in a reader, and read at least// the given number of rows. (Rows are read in chunks, so more than// the target may be read.)const reader = await connection.runAndReadUntil(sql, targetRowCount);const reader = await connection.runAndReadAll(sql, targetRowCount, values);const reader = await connection.runAndReadAll(sql, targetRowCount, values, types);
// Create a streaming result and don't yet retrieve any rows.const result = await connection.stream(sql);const result = await connection.stream(sql, values);const result = await connection.stream(sql, values, types);
// Create a streaming result and don't yet retrieve any rows.// Wrap in a DuckDBDataReader for convenient data retrieval.const reader = await connection.streamAndRead(sql);const reader = await connection.streamAndRead(sql, values);const reader = await connection.streamAndRead(sql, values, types);
// Create a streaming result, wrap in a reader, and read all rows.const reader = await connection.streamAndReadAll(sql);const reader = await connection.streamAndReadAll(sql, values);const reader = await connection.streamAndReadAll(sql, values, types);
// Create a streaming result, wrap in a reader, and read at least// the given number of rows.const reader = await connection.streamAndReadUntil(sql, targetRowCount);const reader = await connection.streamAndReadUntil(sql, targetRowCount, values);const reader = await connection.streamAndReadUntil(sql, targetRowCount, values, types);
// Prepared Statements
// Prepare a possibly-parametered SQL statement to run later.const prepared = await connection.prepare(sql);
// Bind values to the parameters.prepared.bind(values);prepared.bind(values, types);
// Run the prepared statement. These mirror the methods on the connection.const result = prepared.run();
const reader = prepared.runAndRead();const reader = prepared.runAndReadAll();const reader = prepared.runAndReadUntil(targetRowCount);
const result = prepared.stream();
const reader = prepared.streamAndRead();const reader = prepared.streamAndReadAll();const reader = prepared.streamAndReadUntil(targetRowCount);
// Pending Results
// Create a pending result.const pending = await connection.start(sql);const pending = await connection.start(sql, values);const pending = await connection.start(sql, values, types);
// Create a pending, streaming result.const pending = await connection.startStream(sql);const pending = await connection.startStream(sql, values);const pending = await connection.startStream(sql, values, types);
// Create a pending result from a prepared statement.const pending = await prepared.start();const pending = await prepared.startStream();
while (pending.runTask() !== DuckDBPendingResultState.RESULT_READY) { // optionally sleep or do other work between tasks}
// Retrieve the result. If not yet READY, will run until it is.const result = await pending.getResult();
const reader = await pending.read();const reader = await pending.readAll();const reader = await pending.readUntil(targetRowCount);Möglichkeiten, Ergebnisdaten abzurufen
// From a result
// Asynchronously retrieve data for all rows:const columns = await result.getColumns();const columnsJson = await result.getColumnsJson();const columnsObject = await result.getColumnsObject();const columnsObjectJson = await result.getColumnsObjectJson();const rows = await result.getRows();const rowsJson = await result.getRowsJson();const rowObjects = await result.getRowObjects();const rowObjectsJson = await result.getRowObjectsJson();
// From a reader
// First, (asynchronously) read some rows:await reader.readAll();// or:await reader.readUntil(targetRowCount);
// Then, (synchronously) get result data for the rows read:const columns = reader.getColumns();const columnsJson = reader.getColumnsJson();const columnsObject = reader.getColumnsObject();const columnsObjectJson = reader.getColumnsObjectJson();const rows = reader.getRows();const rowsJson = reader.getRowsJson();const rowObjects = reader.getRowObjects();const rowObjectsJson = reader.getRowObjectsJson();
// Individual values can also be read directly:const value = reader.value(columnIndex, rowIndex);
// Using chunks
// If desired, one or more chunks can be fetched from a result:const chunk = await result.fetchChunk();const chunks = await result.fetchAllChunks();
// And then data can be retrieved from each chunk:const columnValues = chunk.getColumnValues(columnIndex);const columns = chunk.getColumns();const rowValues = chunk.getRowValues(rowIndex);const rows = chunk.getRows();
// Or, values can be visited:chunk.visitColumnValues(columnIndex, (value, rowIndex, columnIndex, type) => { /* ... */ });chunk.visitColumns((column, columnIndex, type) => { /* ... */ });chunk.visitColumnMajor( (value, rowIndex, columnIndex, type) => { /* ... */ });chunk.visitRowValues(rowIndex, (value, rowIndex, columnIndex, type) => { /* ... */ });chunk.visitRows((row, rowIndex) => { /* ... */ });chunk.visitRowMajor( (value, rowIndex, columnIndex, type) => { /* ... */ });
// Or converted:// The `converter` argument implements `DuckDBValueConverter`,// which has the single method convertValue(value, type).const columnValues = chunk.convertColumnValues(columnIndex, converter);const columns = chunk.convertColumns(converter);const rowValues = chunk.convertRowValues(rowIndex, converter);const rows = chunk.convertRows(converter);
// The reader abstracts these low-level chunk manipulations// and is recommended for most cases.