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);
    }
  }
});
Copy

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);
    });
  }
});
Copy

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);
    });
  }
})
Copy

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 = 0

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 > 0

Zahl

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 ...
                        }
                      );
    
    Copy
  • Geben Sie den Parameter in den Verbindungskonfigurationsinformationen an:

    var connection = snowflake.createConnection(
          {
          username: 'fakeusername',
          password: 'fakepassword',
          account: 'fakeaccountidentifier',
          jsTreatIntegerAsBigInt: true
          }
        );
    
    Copy

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
    }
  }
});
Copy

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>
Copy

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: ''
  }
});
Copy

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
Copy

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'})
    
    Copy
  • Anweisungsebene

    connection.execute({
      sqlText: sql,
      rowMode: 'array',
      ...
      )}
    
    Copy

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 => eval("(" + rawColumnValue + ")")
    })
    
    Copy
  • 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)
    })
    
    Copy
  • 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)
    })
    
    Copy