Consumo de resultados¶
Retorno de resultados em linha¶
A maneira mais comum de consumir resultados é passar um retorno de chamada complete
para connection.execute()
. Quando a instrução tiver terminado a execução e o resultado estiver pronto para ser consumido, o retorno de chamada complete
é invocado com as linhas de resultado retornadas em linha:
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); } } });
Transmissão de resultados¶
Você também pode consumir um resultado como um fluxo de linhas definindo o parâmetro de conexão streamResult
como true
em connection.execute
ao chamar o método statement.streamRows()
. Ativar esse parâmetro faz com que o método retorne um fluxo Readable
do Node.js, que você pode usar para consumir linhas conforme elas são recebidas. Para obter mais informações sobre o fluxo Readable
, consulte a documentação do Node.js.
Importante
Para qualquer conjunto de resultados que possa exceder a memória padrão do Node, Snowflake recomenda fortemente que você defina streamResult
como true
ao transmitir resultados. Com o valor padrão (false
), o conector armazena todas as linhas em uma matriz antes de transmitir os resultados. Com conjuntos de resultados menores, esse fator normalmente não é um problema. No entanto, com conjuntos de resultados maiores, armazenar todos os resultados na memória pode contribuir para um erro OOM.
Versões recentes do driver Snowflake Node.js (1.6.23 e posteriores) implementam a funcionalidade de pressão de retorno para garantir que, ao consumir resultados, os dados não sejam enviados para o fluxo mais rapidamente do que os dados são lidos do fluxo.
Por exemplo, o seguinte fragmento de código consome os resultados usando o evento 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); }); } });
Resultados do processamento em lote¶
Por padrão, o método statement.streamRows()
produz um fluxo que inclui cada linha do resultado. Entretanto, se você quiser consumir apenas um subconjunto do resultado, ou se quiser consumir linhas de resultados em lotes, pode chamar streamRows()
com argumentos start
e end
. Quando estas opções adicionais são especificadas, apenas as linhas no intervalo solicitado são transmitidas:
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); }); } })
Conversão do tipo de dados¶
Quando linhas de resultados são produzidas, o driver automaticamente mapeia tipos de dados SQL para seus equivalentes JavaScript correspondentes. Por exemplo, os valores do tipo TIMESTAMP e DATE são retornados como objetos de data JavaScript.
Para o mapeamento completo dos tipos de dados JavaScript para SQL, consulte a tabela abaixo:
Tipo de dados SQL
Tipo de dados JavaScript
Notas
VARCHAR, CHAR, CHARACTER, STRING, TEXT
Cadeia de caracteres
INT, INTEGER, BIGINT, SMALLINT
Número
Este é o mapeamento padrão. Use o parâmetro de sessão JS_TREAT_INTEGER_AS_BIGINT para mapear para Bigint JavaScript.
NUMBER(precisão, escala), DECIMAL(p, s), NUMERIC(p, s) onde
scale
= 0Número
Este é o mapeamento padrão. Use o parâmetro de sessão JS_TREAT_INTEGER_AS_BIGINT para mapear para Bigint JavaScript.
NUMBER(precisão, escala), DECIMAL(p, s), NUMERIC(p, s) onde
scale
> 0Número
FLOAT, FLOAT4, FLOAT8, DOUBLE, DOUBLE PRECISION, REAL
Número
TIMESTAMP, TIMESTAMP_LTZ, TIMESTAMP_NTZ, TIMESTAMP_TZ
Data
Valores TIMESTAMP_NTZ são retornados em UTC.
DATE
Data
TIME
Cadeia de caracteres
O tipo de dados TIME em SQL não tem equivalente em JavaScript, portanto é mapeado para uma cadeia de caracteres JavaScript.
BOOLEAN
Booleano
VARIANT, ARRAY, OBJECT
JSON
Busca de tipos de dados inteiros como Bigint¶
Por padrão, colunas INTEGER do Snowflake (incluindo BIGINT
, NUMBER(p, 0)
etc.) são convertidas no tipo de dados Number
do JavaScript. No entanto, os maiores valores inteiros legais do Snowflake são maiores do que os maiores valores numéricos legais JavaScript. Para converter as colunas INTEGER
do Snowflake em JavaScript Bigint
, que pode armazenar valores maiores que JavaScript Number
, defina o parâmetro de sessão JS_TREAT_INTEGER_AS_BIGINT
.
Você pode usar os seguintes métodos para definir esses valores de parâmetro:
Use a instrução ALTER SESSION, como mostrado abaixo:
connection.execute( { sqlText: 'ALTER SESSION SET JS_TREAT_INTEGER_AS_BIGINT = TRUE', complete: function ... } );
Especifique o parâmetro nas informações de configuração da conexão:
var connection = snowflake.createConnection( { username: 'fakeusername', password: 'fakepassword', account: 'fakeaccountidentifier', jsTreatIntegerAsBigInt: true } );
Busca de tipos de dados inteiros como cadeias de caracteres¶
Ao chamar connection.execute()
, você pode usar a opção fetchAsString
para retornar os seguintes tipos de dados como cadeia de caracteres: Boolean
, Number
, Date
, Buffer
e JSON
.
Você pode usar esta opção, por exemplo, para retornar:
Versões formatadas de valores do tipo DATE e TIMESTAMP (ou suas variantes).
Versões de cadeia de caracteres de tipos SQL numéricos que não podem ser convertidas em números JavaScript sem perda de precisão.
O exemplo a seguir usa fetchAsString
para converter um valor Number
de alta precisão em uma cadeia de caracteres:
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
}
}
});
Análise de dados XML¶
A partir da versão 1.7.0 do driver, você pode usar as seguintes opções de configuração da biblioteca fast-xml-parser para personalizar como o driver processa os atributos do documento XML ao consultar colunas com conteúdo XML. Para obter mais informações sobre essas opções suportadas e como elas afetam a análise de dados XML, consulte Opções de xmlParserConfig.
Por padrão, o driver Node.js ignora os atributos do elemento XML ao retornar dados XML de uma consulta. Por exemplo, no conteúdo XML a seguir, o elemento <piece>
inclui um atributo 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>
Por padrão, quando o driver Node.js retorna o conjunto de resultados, ele ignora o atributo id
e retorna a saída a seguir. Observe que os nomes e valores dos atributos não estão incluídos.
{
exhibit: {
piece: [
{
"name": "Mona Lisa",
"artist": "Leonardo da Vinci",
"year": "1503",
},
{
"name": "The Starry Night",
"artist": "Vincent van Gogh",
"year": "1889",
}
]
}
}
Para definir as opções do fast-xml-parser, crie um elemento xmlParserConfig
semelhante ao exemplo a seguir:
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: '' } });
Com essas configurações, o driver analisa os dados XML e produz o seguinte:
{
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' }
}
Como retornar conjuntos de resultados que contêm nomes de colunas duplicados¶
Na versão 1.8.0, o driver Snowflake Node.js introduziu uma nova opção de configuração rowMode que permite especificar como você deseja que o driver retorne conjuntos de resultados que contêm nomes de colunas duplicados.
Antes da versão 1.8.0, o driver Snowflake Node.js sempre retornava o conjunto de resultados de um comando SELECT como um objeto JavaScript. Nos casos em que o conjunto de resultados continha nomes e valores de colunas duplicados, alguns elementos poderiam ser omitidos devido à maneira como os objetos JavaScript manipulam nomes duplicados.
A opção rowMode
permite especificar como os dados do conjunto de resultados são retornados para evitar possível perda de informações, inclusive como:
array
object
(padrão)object_with_renamed_duplicated_columns
Para ilustrar, suponha que você envie a seguinte consulta:
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
Com base no valor de rowMode
, o driver retorna os conjuntos de resultados da seguinte forma:
object
(ou não definido){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};
Você pode definir o parâmetro rowMode
no nível de configuração da conexão ou da instrução, conforme mostrado abaixo. Se definido em ambos os locais, o valor do nível de instrução terá precedência.
Nível de configuração
snowflake.createConnection({ account: account, username: username, ... rowMode: 'array'})
Nível de instrução
connection.execute({ sqlText: sql, rowMode: 'array', ... )}
Personalização de como os conjuntos de resultados processam dados JSON e XML¶
O driver Snowflake Node.js fornece os seguintes analisadores padrão para processar dados JSON e XML em conjuntos de resultados:
JSON: retorna o resultado de um novo objeto
Function
.XML: fast-xml-parser.
O módulo
fast-xml-parser
padrão oferece suporte a um subconjunto de recursos, conforme descrito em Análise de dados XML.
Se preferir usar um analisador personalizado, você pode usar os seguintes exemplos para configurá-los:
Use o analisador eval JSON, que o driver usava antes da versão 1.6.21:
const snowflake = require('snowflake-sdk'); snowflake.configure({ jsonColumnVariantParser: rawColumnValue => JSON.parse(rawColumnValue) })
Use o analisador
fast-xml-parser
, com a capacidade de personalizar todas as suas opções:const snowflake = require('snowflake-sdk'); snowflake.configure({ xmlColumnVariantParser: rawColumnValue => new (require("fast-xml-parser")).XMLParser().parse(rawColumnValue) })
Configure analisadores personalizados para ambos na mesma declaração:
const snowflake = require('snowflake-sdk'); snowflake.configure({ jsonColumnVariantParser: rawColumnValue => JSON.parse(rawColumnValue), xmlColumnVariantParser: rawColumnValue => new (require("fast-xml-parser")).XMLParser().parse(rawColumnValue) })