Verwenden von Ergebnissen¶
Inline-Rückgabe von Ergebnissen¶
Die gebräuchlichste Art, Ergebnisse zu verwenden, ist die Übergabe eines complete
-Callbacks an connection.execute()
. Wenn die Ausführung der Anweisung beendet und das Ergebnis zur Verwendung bereit ist, wird der complete
-Callback gestartet, und die Ergebniszeilen werden inline zurückgegeben:
connection.execute({ sqlText: 'SELECT * FROM sometable', complete: function(err, stmt, rows) { if (err) { console.error('Failed to execute statement due to the following error: ' + err.message); } else { console.log('Number of rows produced: ' + rows.length); } } });
Streamen von Ergebnissen¶
Sie können ein Ergebnis auch als Stream von Zeilen verbrauchen, indem Sie beim Aufruf der Methode statement.streamRows()
in connection.execute
den Verbindungsparameter streamResult
auf true
setzen. Wenn Sie diesen Parameter aktivieren, gibt die Methode einen Node.js-Readable
-Stream zurück, den Sie verwenden können, um die empfangenen Zeilen weiterzuverarbeiten. Weitere Informationen zum Readable
-Stream finden Sie in der Dokumentation zu Node.js.
Wichtig
Wenn bei einem Resultset die Gefahr besteht, dass es den Standardspeicher von Node überschreitet, empfiehlt Snowflake dringend, dass Sie beim Streamen der Ergebnisse streamResult
auf true
setzen. Mit dem Standardwert (false
) speichert der Konnektor erst alle Zeilen in einem Array, bevor er die Ergebnisse streamt. Bei kleineren Resultsets ist dieser Faktor normalerweise kein Problem. Bei größeren Resultsets kann das Speichern aller Ergebnisse im Speicher jedoch zu einem OOM-Fehler führen.
Neuere Versionen des Snowflake Node.js-Treibers (ab 1.6.23) implementieren Backpressure-Funktionen, um sicherzustellen, dass beim Verarbeiten von Ergebnissen die Daten nicht schneller in den Stream gepusht werden, als sie aus dem Stream gelesen werden.
Das folgende Codefragment verarbeitet zum Beispiel die Ergebnisse unter Verwendung des Ereignisses Readable
:
var connection = snowflake.createConnection({ account: process.env.SFACCOUNT, username: process.env.SFUSER, // ... streamResult: true }); // [..rest of the code..] connection.execute({ sqlText: "select L_COMMENT from SNOWFLAKE_SAMPLE_DATA.TPCH_SF100.LINEITEM limit 100000;", streamResult: true, complete: function (err, stmt) { var stream = stmt.streamRows(); // Read data from the stream when it is available stream.on('readable', function (row) { while ((row = this.read()) !== null) { console.log(row); } }).on('end', function () { console.log('done'); }).on('error', function (err) { console.log(err); }); } });
Batchverarbeitung von Ergebnissen¶
Standardmäßig wird mit der statement.streamRows()
-Methode ein Stream produziert, der jede Zeile im Ergebnis enthält. Wenn Sie jedoch nur eine Teilmenge des Ergebnisses weiterverwenden möchten oder wenn Ergebniszeilen in Batches verwendet werden sollen, können Sie streamRows()
mit start
- und end
-Argumenten aufrufen. Bei Angabe dieser zusätzlichen Optionen werden nur Zeilen im geforderten Bereich gestreamt:
connection.execute({ sqlText: 'SELECT * FROM sometable', streamResult: true, // prevent rows from being returned inline in the complete callback complete: function(err, stmt, rows) { // no rows returned inline because streamResult was set to true console.log('rows: ' + rows); // 'rows: undefined' // only consume at most the last 5 rows in the result rows = []; stmt.streamRows({ start: Math.max(0, stmt.getNumRows() - 5), end: stmt.getNumRows() - 1, }) .on('error', function(err) { console.error('Unable to consume requested rows'); }) .on('data', function(row) { rows.push(row); }) .on('end', function() { console.log('Number of rows consumed: ' + rows.length); }); } })
Umwandeln des Datentyps¶
Wenn Ergebniszeilen erzeugt werden, ordnet der Treiber SQL-Datentypen automatisch den entsprechenden JavaScript-Äquivalenten zu. Beispielsweise werden Werte der Typen TIMESTAMP und DATE als JavaScript Date-Objekte zurückgegeben.
Die folgende Tabelle enthält die vollständige Zuordnung von JavaScript- zu SQL-Datentypen:
SQL-Datentyp
JavaScript-Datentyp
Anmerkungen
VARCHAR, CHAR, CHARACTER, STRING, TEXT
String
INT, INTEGER, BIGINT, SMALLINT
Zahl
Dies ist die Standardzuordnung. Verwenden Sie den Sitzungsparameter JS_TREAT_INTEGER_AS_BIGINT, um eine Zuordnung zu JavaScript Bigint vorzunehmen.
NUMBER(Genauigkeit, Skalierung), DECIMAL(p, s), NUMERIC(p, s), wobei
scale
= 0Zahl
Dies ist die Standardzuordnung. Verwenden Sie den Sitzungsparameter JS_TREAT_INTEGER_AS_BIGINT, um eine Zuordnung zu JavaScript Bigint vorzunehmen.
NUMBER(Genauigkeit, Skalierung), DECIMAL(p, s), NUMERIC(p, s) wobei
scale
> 0Zahl
FLOAT, FLOAT4, FLOAT8, DOUBLE, DOUBLE PRECISION, REAL
Zahl
TIMESTAMP, TIMESTAMP_LTZ, TIMESTAMP_NTZ, TIMESTAMP_TZ
Date
TIMESTAMP_NTZ Werte werden in UTC zurückgegeben.
DATE
Date
TIME
String
Beachten Sie, dass der TIME-Datentyp in SQL kein Äquivalent in JavaScript hat, sodass er auf eine JavaScript-Zeichenfolge (String) abgebildet wird.
BOOLEAN
Boolean
VARIANT, ARRAY, OBJECT
JSON
Abrufen von Ganzzahl-Datentypen als Bigint¶
Standardmäßig werden die INTEGER-Spalten von Snowflake (einschließlich BIGINT
, NUMBER(p, 0)
usw.) in den JavaScript-Datentyp Number
konvertiert. Die größten zulässigen Snowflake-Ganzzahlwerte sind jedoch größer als die größten zulässigen JavaScript-Zahlenwerte. Um Snowflake-INTEGER
-Spalten in JavaScript Bigint
zu konvertieren, in denen größere Werte als JavaScript Number
gespeichert werden können, legen Sie den Sitzungsparameter JS_TREAT_INTEGER_AS_BIGINT
fest.
Sie können die folgenden Methoden verwenden, um diese Parameterwerte einzustellen:
Verwenden Sie die ALTER SESSION-Anweisung wie folgt:
connection.execute( { sqlText: 'ALTER SESSION SET JS_TREAT_INTEGER_AS_BIGINT = TRUE', complete: function ... } );
Geben Sie den Parameter in den Verbindungskonfigurationsinformationen an:
var connection = snowflake.createConnection( { username: 'fakeusername', password: 'fakepassword', account: 'fakeaccountidentifier', jsTreatIntegerAsBigInt: true } );
Abrufen von Datentypen als Zeichenfolgen (String)¶
Wenn Sie connection.execute()
aufrufen, können Sie die Option fetchAsString
verwenden, um die folgenden Datentypen als Zeichenfolgen zurückzugeben: Boolean
, Number
, Date
, Buffer
und JSON
.
Sie können diese Option beispielsweise verwenden, um Folgendes zurückzugeben:
Formatierte Versionen von Werten des Typs DATE und TIMESTAMP (oder deren Varianten).
Zeichenfolgeversionen von numerischen SQL-Typen, die nicht ohne Genauigkeitsverlust in JavaScript-Zahlen umgewandelt werden können.
Im folgenden Beispiel wird fetchAsString
verwendet, um einen hochpräzisen Number
-Wert in einen String-Wert zu konvertieren:
connection.execute({
sqlText: 'SELECT 1.123456789123456789123456789 as "c1"',
fetchAsString: ['Number'],
complete: function(err, stmt, rows) {
if (err) {
console.error('Failed to execute statement due to the following error: ' + err.message);
} else {
console.log('c1: ' + rows[0].c1); // c1: 1.123456789123456789123456789
}
}
});
Parsen von XML-Daten¶
Ab Version 1.7.0 des Treibers können Sie die folgenden fast-xml-parser-Bibliothekskonfigurationsoptionen verwenden, um festzulegen, wie der Treiber bei der Abfrage von Spalten mit XML-Inhalt die XML-Dokumentattribute verarbeitet. Weitere Informationen zu diesen unterstützten Optionen und deren Auswirkung auf das Parsen von XML-Daten finden Sie unter xmlParserConfig-Optionen.
Standardmäßig ignoriert der Node.js-Treiber die XML-Elementattribute, wenn von einer Abfrage XML-Daten zurückgegeben werden. Der folgende XML-Inhalt enthält beispielsweise das Element <piece>
mit einem Attribut id
:
<exhibit name="Art Show">
<piece id="000001">
<name>Mona Lisa</name>
<artist>Leonardo da Vinci</artist>
<year>1503</year>
</piece>
<piece id="000002">
<name>The Starry Night</name>
<artist>Vincent van Gogh</artist>
<year>1889</year>
</piece>
</exhibit>
Wenn der Node.js-Treiber das Resultset zurückgibt, wird das Attribut id
standardmäßig ignoriert, und es wird die folgende Ausgabe zurückgegeben. Beachten Sie, dass die Attributnamen und -werte nicht enthalten sind.
{
exhibit: {
piece: [
{
"name": "Mona Lisa",
"artist": "Leonardo da Vinci",
"year": "1503",
},
{
"name": "The Starry Night",
"artist": "Vincent van Gogh",
"year": "1889",
}
]
}
}
Um die Optionen fast-xml-parser einzustellen, erstellen Sie ein xmlParserConfig
-Element ähnlich dem folgenden Beispiel:
const snowflake = require('snowflake-sdk'); snowflake.configure({ xmlParserConfig: { /* Parameters that you can override * ignoreAttributes - default true, * attributeNamePrefix - default '@_', * attributesGroupName - default unset, * alwaysCreateTextNode - default false */ ignoreAttributes: false, attributesGroupName: '@', attributeNamePrefix: '' } });
Mit diesen Einstellungen parst der Treiber die XML-Daten und erzeugt Folgendes:
{
exhibit: {
piece: [
{
"name": "Mona Lisa",
"artist": "Leonardo da Vinci",
"year": "1503",
'@': { id: '000001' }
},
{
"name": "The Starry Night",
"artist": "Vincent van Gogh",
"year": "1889",
'@': { id: '000002' }
}
],
'@': { name: 'Art Show' }
}
Rückgabe von Resultsets, die doppelte Spaltennamen enthalten¶
In Version 1.8.0 hat der Snowflake Node.js-Treiber eine neue Konfigurationsoption rowMode eingeführt, mit der Sie angeben können, wie der Treiber Resultsets zurückgeben soll, die doppelte Spaltennamen enthalten.
Vor Version 1.8.0 gab der Snowflake Node.js-Treiber das Resultset eines SELECT-Befehls immer als JavaScript-Objekt zurück. In Fällen, in denen das Resultset doppelte Spaltennamen und -werte enthielt, konnten einige Elemente aufgrund der Art und Weise, wie JavaScript-Objekte doppelte Namen behandeln, ausgelassen werden.
Mit der Option rowMode
können Sie angeben, wie die Daten dea Resultsets zurückgegeben werden, um einen möglichen Informationsverlust zu vermeiden, z. B. als:
array
object
(Standard)object_with_renamed_duplicated_columns
Zur Veranschaulichung: Nehmen Sie an, Sie stellen die folgende Abfrage:
select *
from (select 'a' as key, 1 as foo, 3 as name) as table1
join (select 'a' as key, 2 as foo, 3 as name2) as table2 on table1.key = table2.key
join (select 'a' as key, 3 as foo) as table3 on table1.key = table3.key
Basierend auf dem Wert von rowMode
gibt der Treiber das Resultset wie folgt zurück:
object
(oder nicht gesetzt){KEY: 'a', FOO: 3, NAME: 3, NAME2: 3};
array
['a', 1, 3, 'a', 2, 3, 'a', 3];
object_with_renamed_duplicated_columns
{KEY: 'a', FOO: 1, NAME: 3, KEY_2: 'a', FOO_2: 2, NAME2: 3, KEY_3: 'a', FOO_3: 3};
Sie können den Parameter rowMode
auf der Ebene der Verbindungs- oder Anweisungskonfiguration einstellen, wie unten gezeigt. Wenn sie an beiden Stellen gesetzt sind, hat der Wert der Anweisungsebene Vorrang.
Konfigurationsebene
snowflake.createConnection({ account: account, username: username, ... rowMode: 'array'})
Anweisungsebene
connection.execute({ sqlText: sql, rowMode: 'array', ... )}
Anpassen der Verarbeitung von Resultsets mit JSON- und XML-Daten¶
Der Snowflake Node.js-Treiber bietet die folgenden Standard-Parser für die Verarbeitung von JSON- und XML-Daten in Resultsets:
JSON: Gibt das Ergebnis eines neuen
Function
-Objekts zurück.XML: fast-xml-parser.
Das Standardmodul
fast-xml-parser
unterstützt eine Teilmenge von Features, wie in Parsen von XML-Daten beschrieben.
Wenn Sie es vorziehen, einen kundenspezifischen Parser zu verwenden, können Sie ihn anhand der folgenden Beispiele konfigurieren:
Verwenden Sie den Parser eval JSON, den der Treiber vor der Version 1.6.21 verwendet hat:
const snowflake = require('snowflake-sdk'); snowflake.configure({ jsonColumnVariantParser: rawColumnValue => JSON.parse(rawColumnValue) })
Verwenden Sie den Parser
fast-xml-parser
mit der Möglichkeit, alle Optionen anzupassen:const snowflake = require('snowflake-sdk'); snowflake.configure({ xmlColumnVariantParser: rawColumnValue => new (require("fast-xml-parser")).XMLParser().parse(rawColumnValue) })
Konfigurieren Sie kundenspezifische Parser für beide in derselben Erklärung:
const snowflake = require('snowflake-sdk'); snowflake.configure({ jsonColumnVariantParser: rawColumnValue => JSON.parse(rawColumnValue), xmlColumnVariantParser: rawColumnValue => new (require("fast-xml-parser")).XMLParser().parse(rawColumnValue) })