

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# Driver Amazon QLDB para Node.js: referência do livro de receitas
<a name="driver-cookbook-nodejs"></a>

**Importante**  
Aviso de fim do suporte: os clientes existentes poderão usar o Amazon QLDB até o final do suporte em 31/07/2025. Para obter mais detalhes, consulte [Migrar um Amazon QLDB Ledger para o Amazon](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/) Aurora PostgreSQL.

Este guia de referência mostra casos de uso comuns do driver Amazon QLDB para Node.js. Ele fornece JavaScript exemplos de TypeScript código que demonstram como usar o driver para executar operações básicas de *criação, leitura, atualização e exclusão* (CRUD). Também inclui exemplos de código para processamento de dados do Amazon Ion. Além disso, este guia destaca as práticas recomendadas para tornar as transações idempotentes e implantar restrições de exclusividade.

**Contents**
+ [Importação do driver](#cookbook-nodejs.importing)
+ [Instanciação do driver](#cookbook-nodejs.instantiating)
+ [Operações de CRUD](#cookbook-nodejs.crud)
  + [Criar tabelas](#cookbook-nodejs.crud.creating-tables)
  + [Criar índices](#cookbook-nodejs.crud.creating-indexes)
  + [Ler documentos](#cookbook-nodejs.crud.reading)
    + [Usar parâmetros de consulta](#cookbook-nodejs.reading-using-params)
  + [Inserir documentos](#cookbook-nodejs.crud.inserting)
    + [Como inserir vários documentos em uma instrução](#cookbook-nodejs.crud.inserting.multiple)
  + [Como atualizar documentos](#cookbook-nodejs.crud.updating)
  + [Como excluir documentos](#cookbook-nodejs.crud.deleting)
  + [Como executar várias instruções em uma transação](#cookbook-nodejs.crud.multi-statement)
  + [Lógica de novas tentativas](#cookbook-nodejs.crud.retry-logic)
  + [Implementação de restrições de exclusividade](#cookbook-nodejs.crud.uniqueness-constraints)
+ [Como trabalhar com o Amazon Ion](#cookbook-nodejs.ion)
  + [Importar o módulo Ion](#cookbook-nodejs.ion.import)
  + [Criação de tipos de Ion](#cookbook-nodejs.ion.creating-types)
  + [Obter um despejo de binário Ion](#cookbook-nodejs.ion.getting-binary)
  + [Obter um despejo de texto Ion](#cookbook-nodejs.ion.getting-text)

## Importação do driver
<a name="cookbook-nodejs.importing"></a>

O exemplo de código a seguir importa o driver.

------
#### [ JavaScript ]

```
var qldb = require('amazon-qldb-driver-nodejs');
var ionjs = require('ion-js');
```

------
#### [ TypeScript ]

```
import { QldbDriver, TransactionExecutor } from "amazon-qldb-driver-nodejs";
import { dom, dumpBinary, load } from "ion-js";
```

------

**nota**  
Este exemplo também importa o pacote Amazon Ion (`ion-js`). Você precisa desse pacote para processar dados de íons ao executar algumas operações de dados nesta referência. Para saber mais, consulte [Como trabalhar com o Amazon Ion](#cookbook-nodejs.ion).

## Instanciação do driver
<a name="cookbook-nodejs.instantiating"></a>

O exemplo de código a seguir cria uma instância do driver que se conecta a um nome de ledger especificado usando as configurações padrão.

------
#### [ JavaScript ]

```
const qldbDriver = new qldb.QldbDriver("vehicle-registration");
```

------
#### [ TypeScript ]

```
const qldbDriver: QldbDriver = new QldbDriver("vehicle-registration");
```

------

## Operações de CRUD
<a name="cookbook-nodejs.crud"></a>

O QLDB *executa operações de criação, leitura, atualização e exclusão* (CRUD) como parte de uma transação.

**Atenção**  
Como prática recomendada, torne suas transações de gravação estritamente idempotentes.

**Tornar as transações idempotentes**

Recomendamos que você torne as transações de gravação idempotentes para evitar efeitos colaterais inesperados no caso de novas tentativas. Uma transação é *idempotente* se puder ser executada várias vezes e produzir resultados idênticos a cada vez.

Por exemplo, considere uma transação que insere um documento em uma tabela chamada `Person`. A transação deve primeiro verificar se o documento já existe ou não na tabela. Sem essa verificação, a tabela pode acabar com documentos duplicados.

Suponha que o QLDB confirme com sucesso a transação no lado do servidor, mas o tempo do cliente expire enquanto espera por uma resposta. Se a transação não for idempotente, o mesmo documento poderá ser inserido mais de uma vez no caso de uma nova tentativa.

**Usar índices para evitar varreduras completas da tabela**

Também recomendamos executar instruções com uma cláusula de predicado `WHERE` usando um operador de *igualdade* em um campo indexado ou em um ID de documento, por exemplo, `WHERE indexedField = 123` ou `WHERE indexedField IN (456, 789)`. Sem essa pesquisa indexada, o QLDB precisa fazer uma varredura de tabela, o que pode levar a tempos limite de transação ou conflitos *otimistas de controle de simultaneidade* (OCC).

Para obter mais informações sobre OCC, consulte [Modelo de simultaneidade do Amazon QLDB](concurrency.md).

**Transações criadas implicitamente**

O método [QldbDriver.executeLambda](https://amazon-qldb-docs.s3.amazonaws.com/drivers/nodejs/2.2.0/classes/_src_qldbdriver_.qldbdriver.html#executelambda) aceita uma função lambda que recebe uma instância de [TransactionExecutor](https://amazon-qldb-docs.s3.amazonaws.com/drivers/nodejs/2.2.0/classes/_src_transactionexecutor_.transactionexecutor.html), que você pode usar para executar instruções. A instância de `TransactionExecutor` envolve uma transação criada implicitamente.

Você pode executar instruções na função do Lambda usando o método de [execução](https://amazon-qldb-docs.s3.amazonaws.com/drivers/nodejs/2.2.0/classes/_src_transactionexecutor_.transactionexecutor.html#execute) da transação. O driver confirma implicitamente a transação quando a função do Lambda retorna.

**nota**  
O método `execute` suporta valores nos tipos Amazon Ion e nos tipos nativos do Node.js. Se você passar um tipo nativo do Node.js como argumento para `execute`, o driver o converterá em um tipo Ion usando o módulo `ion-js` (desde que a conversão para o determinado tipo de dados do Node.js seja suportada). Para ver os tipos de dados e as regras de conversão compatíveis, consulte o Ion JavaScript DOM [README.](https://github.com/amzn/ion-js/blob/master/src/dom/README.md)

As seções a seguir mostram como executar operações CRUD básicas, especificar a lógica de repetição personalizada e implementar restrições de exclusividade.

**Contents**
+ [Criar tabelas](#cookbook-nodejs.crud.creating-tables)
+ [Criar índices](#cookbook-nodejs.crud.creating-indexes)
+ [Ler documentos](#cookbook-nodejs.crud.reading)
  + [Usar parâmetros de consulta](#cookbook-nodejs.reading-using-params)
+ [Inserir documentos](#cookbook-nodejs.crud.inserting)
  + [Como inserir vários documentos em uma instrução](#cookbook-nodejs.crud.inserting.multiple)
+ [Como atualizar documentos](#cookbook-nodejs.crud.updating)
+ [Como excluir documentos](#cookbook-nodejs.crud.deleting)
+ [Como executar várias instruções em uma transação](#cookbook-nodejs.crud.multi-statement)
+ [Lógica de novas tentativas](#cookbook-nodejs.crud.retry-logic)
+ [Implementação de restrições de exclusividade](#cookbook-nodejs.crud.uniqueness-constraints)

### Criar tabelas
<a name="cookbook-nodejs.crud.creating-tables"></a>

------
#### [ JavaScript ]

```
(async function() {
    await qldbDriver.executeLambda(async (txn) => {
        await txn.execute("CREATE TABLE Person");
    });
})();
```

------
#### [ TypeScript ]

```
(async function(): Promise<void> {
    await qldbDriver.executeLambda(async (txn: TransactionExecutor) => {
        await txn.execute('CREATE TABLE Person');
    });
}());
```

------

### Criar índices
<a name="cookbook-nodejs.crud.creating-indexes"></a>

------
#### [ JavaScript ]

```
(async function() {
    await qldbDriver.executeLambda(async (txn) => {
        await txn.execute("CREATE INDEX ON Person (GovId)");
    });
})();
```

------
#### [ TypeScript ]

```
(async function(): Promise<void> {
    await qldbDriver.executeLambda(async (txn: TransactionExecutor) => {
        await txn.execute('CREATE INDEX ON Person (GovId)');
    });
}());
```

------

### Ler documentos
<a name="cookbook-nodejs.crud.reading"></a>

------
#### [ JavaScript ]

```
(async function() {
    // Assumes that Person table has documents as follows:
    // { "GovId": "TOYENC486FH", "FirstName": "Brent" }
    await qldbDriver.executeLambda(async (txn) => {
        const results = (await txn.execute("SELECT * FROM Person WHERE GovId = 'TOYENC486FH'")).getResultList();
        for (let result of results) {
            console.log(result.get('GovId')); // prints [String: 'TOYENC486FH']
            console.log(result.get('FirstName')); // prints [String: 'Brent']
        }
    });
}());
```

------
#### [ TypeScript ]

```
(async function(): Promise<void> {
    // Assumes that Person table has documents as follows:
    // { "GovId": "TOYENC486FH", "FirstName": "Brent" }
    await qldbDriver.executeLambda(async (txn: TransactionExecutor) => {
        const results: dom.Value[] = (await txn.execute("SELECT * FROM Person WHERE GovId = 'TOYENC486FH'")).getResultList();
        for (let result of results) {
            console.log(result.get('GovId')); // prints [String: 'TOYENC486FH']
            console.log(result.get('FirstName')); // prints [String: 'Brent']
        }
    });
}());
```

------

#### Usar parâmetros de consulta
<a name="cookbook-nodejs.reading-using-params"></a>

O exemplo de código a seguir usa um parâmetro de consulta do tipo nativo.

------
#### [ JavaScript ]

```
(async function() {
    // Assumes that Person table has documents as follows:
    // { "GovId": "TOYENC486FH", "FirstName": "Brent" }
    await qldbDriver.executeLambda(async (txn) => {
        const results = (await txn.execute('SELECT * FROM Person WHERE GovId = ?', 'TOYENC486FH')).getResultList();
        for (let result of results) {
            console.log(result.get('GovId')); // prints [String: 'TOYENC486FH']
            console.log(result.get('FirstName')); // prints [String: 'Brent']
        }
    });
}());
```

------
#### [ TypeScript ]

```
(async function(): Promise<void> {
    // Assumes that Person table has documents as follows:
    // { "GovId": "TOYENC486FH", "FirstName": "Brent" }
    await qldbDriver.executeLambda(async (txn: TransactionExecutor) => {
        const results: dom.Value[] = (await txn.execute('SELECT * FROM Person WHERE GovId = ?', 'TOYENC486FH')).getResultList();
        for (let result of results) {
            console.log(result.get('GovId')); // prints [String: 'TOYENC486FH']
            console.log(result.get('FirstName')); // prints [String: 'Brent']
        }
    });
}());
```

------

O exemplo de código a seguir usa um parâmetro de consulta do tipo Ion.

------
#### [ JavaScript ]

```
(async function() {
    await qldbDriver.executeLambda(async (txn) => {
        const govId = ionjs.load("TOYENC486FH");

        const results = (await txn.execute('SELECT * FROM Person WHERE GovId = ?', govId)).getResultList();
        for (let result of results) {
            console.log(result.get('GovId')); // prints [String: 'TOYENC486FH']
            console.log(result.get('FirstName')); // prints [String: 'Brent']
        }
    });
}());
```

------
#### [ TypeScript ]

```
(async function(): Promise<void> {
    await qldbDriver.executeLambda(async (txn: TransactionExecutor) => {
        const govId: dom.Value = load("TOYENC486FH");

        const results: dom.Value[] = (await txn.execute('SELECT * FROM Person WHERE GovId = ?', govId)).getResultList();
        for (let result of results) {
            console.log(result.get('GovId')); // prints [String: 'TOYENC486FH']
            console.log(result.get('FirstName')); // prints [String: 'Brent']
        }
    });
}());
```

------

O exemplo de código a seguir usa múltiplos parâmetros de consulta.

------
#### [ JavaScript ]

```
(async function() {
    await qldbDriver.executeLambda(async (txn) => {
        const results = (await txn.execute('SELECT * FROM Person WHERE GovId = ? AND FirstName = ?', 'TOYENC486FH', 'Brent')).getResultList();
        for (let result of results) {
            console.log(result.get('GovId')); // prints [String: 'TOYENC486FH']
            console.log(result.get('FirstName')); // prints [String: 'Brent']
        }
    });
}());
```

------
#### [ TypeScript ]

```
(async function(): Promise<void> {
    await qldbDriver.executeLambda(async (txn: TransactionExecutor) => {
        const results: dom.Value[] = (await txn.execute('SELECT * FROM Person WHERE GovId = ? AND FirstName = ?', 'TOYENC486FH', 'Brent')).getResultList();
        for (let result of results) {
            console.log(result.get('GovId')); // prints [String: 'TOYENC486FH']
            console.log(result.get('FirstName')); // prints [String: 'Brent']
        }
    });
}());
```

------

O exemplo de código a seguir usa uma lista de parâmetros de consulta.

------
#### [ JavaScript ]

```
(async function() {
    await qldbDriver.executeLambda(async (txn) => {
        const govIds = ['TOYENC486FH','LOGANB486CG','LEWISR261LL'];
        /*
        Assumes that Person table has documents as follows:
        { "GovId": "TOYENC486FH", "FirstName": "Brent" }
        { "GovId": "LOGANB486CG", "FirstName": "Brent" }
        { "GovId": "LEWISR261LL", "FirstName": "Raul" }
        */
        const results = (await txn.execute('SELECT * FROM Person WHERE GovId IN (?,?,?)', ...govIds)).getResultList();
        for (let result of results) {
            console.log(result.get('GovId'));
            console.log(result.get('FirstName'));
            /*
            prints:
            [String: 'TOYENC486FH']
            [String: 'Brent']
            [String: 'LOGANB486CG']
            [String: 'Brent']
            [String: 'LEWISR261LL']
            [String: 'Raul']
            */
        }
    });
}());
```

------
#### [ TypeScript ]

```
(async function(): Promise<void> {
    await qldbDriver.executeLambda(async (txn: TransactionExecutor) => {
        const govIds: string[] = ['TOYENC486FH','LOGANB486CG','LEWISR261LL'];
        /*
        Assumes that Person table has documents as follows:
        { "GovId": "TOYENC486FH", "FirstName": "Brent" }
        { "GovId": "LOGANB486CG", "FirstName": "Brent" }
        { "GovId": "LEWISR261LL", "FirstName": "Raul" }
        */
        const results: dom.Value[] = (await txn.execute('SELECT * FROM Person WHERE GovId IN (?,?,?)', ...govIds)).getResultList();
        for (let result of results) {
            console.log(result.get('GovId'));
            console.log(result.get('FirstName'));
            /*
            prints:
            [String: 'TOYENC486FH']
            [String: 'Brent']
            [String: 'LOGANB486CG']
            [String: 'Brent']
            [String: 'LEWISR261LL']
            [String: 'Raul']
            */
        }
    });
}());
```

------

**nota**  
Quando você executa uma consulta sem uma pesquisa indexada, ela invoca uma verificação completa da tabela. Neste exemplo, recomendamos ter um [índice](ql-reference.create-index.md) no campo `GovId` para otimizar o desempenho. Sem um índice em `GovId`, as consultas podem ter mais latência e também podem levar a exceções de conflitos de OCC ou a tempos limite de transação.

### Inserir documentos
<a name="cookbook-nodejs.crud.inserting"></a>

Os exemplos de código a seguir inserem os tipos de dados nativos.

------
#### [ JavaScript ]

```
(async function() {
    await qldbDriver.executeLambda(async (txn) => {
        // Check if doc with GovId:TOYENC486FH exists
        // This is critical to make this transaction idempotent
        const results = (await txn.execute('SELECT * FROM Person WHERE GovId = ?', 'TOYENC486FH')).getResultList();
        // Insert the document after ensuring it doesn't already exist
        if (results.length == 0) {
            const doc = {
                'FirstName': 'Brent',
                'GovId': 'TOYENC486FH',
            };
            await txn.execute('INSERT INTO Person ?', doc);
        }
    });
}());
```

------
#### [ TypeScript ]

```
(async function(): Promise<void> {
    await qldbDriver.executeLambda(async (txn: TransactionExecutor) => {
        // Check if doc with GovId:TOYENC486FH exists
        // This is critical to make this transaction idempotent
        const results: dom.Value[] = (await txn.execute('SELECT * FROM Person WHERE GovId = ?', 'TOYENC486FH')).getResultList();
        // Insert the document after ensuring it doesn't already exist
        if (results.length == 0) {
            const doc: Record<string, string> = {
                'FirstName': 'Brent',
                'GovId': 'TOYENC486FH',
            };
            await txn.execute('INSERT INTO Person ?', doc);
        }
    });
}());
```

------

Os exemplos de código a seguir inserem os tipos de dados Ion.

------
#### [ JavaScript ]

```
(async function() {
    await qldbDriver.executeLambda(async (txn) => {
        // Check if doc with GovId:TOYENC486FH exists
        // This is critical to make this transaction idempotent
        const results = (await txn.execute('SELECT * FROM Person WHERE GovId = ?', 'TOYENC486FH')).getResultList();
        // Insert the document after ensuring it doesn't already exist
        if (results.length == 0) {
            const doc = {
                'FirstName': 'Brent',
                'GovId': 'TOYENC486FH',
            };
            // Create a sample Ion doc
            const ionDoc = ionjs.load(ionjs.dumpBinary(doc));

            await txn.execute('INSERT INTO Person ?', ionDoc);
        }
    });
}());
```

------
#### [ TypeScript ]

```
(async function(): Promise<void> {
    await qldbDriver.executeLambda(async (txn: TransactionExecutor) => {
        // Check if doc with GovId:TOYENC486FH exists
        // This is critical to make this transaction idempotent
        const results: dom.Value[] = (await txn.execute('SELECT * FROM Person WHERE GovId = ?', 'TOYENC486FH')).getResultList();
        // Insert the document after ensuring it doesn't already exist
        if (results.length == 0) {
            const doc: Record<string, string> = {
                'FirstName': 'Brent',
                'GovId': 'TOYENC486FH',
            };
            // Create a sample Ion doc
            const ionDoc: dom.Value = load(dumpBinary(doc));

            await txn.execute('INSERT INTO Person ?', ionDoc);
        }
    });
}());
```

------

Essa transação insere um documento na tabela `Person`. Antes de inserir, ele primeiro verifica se o documento já existe na tabela. **Essa verificação torna a transação idempotente por natureza.** Mesmo que você execute essa transação várias vezes, ela não causará efeitos colaterais indesejados.

**nota**  
Neste exemplo, recomendamos ter um índice no campo `GovId` para otimizar o desempenho. Sem um índice em `GovId`, as instruções podem ter mais latência e também podem levar a exceções de conflitos de OCC ou a tempos limite de transação.

#### Como inserir vários documentos em uma instrução
<a name="cookbook-nodejs.crud.inserting.multiple"></a>

Para inserir vários documentos usando uma única instrução [INSERT](ql-reference.insert.md), você pode passar um parâmetro do tipo [lista](driver-working-with-ion.md#driver-ion-list) para a instrução da seguinte maneira.

```
// people is a list
txn.execute("INSERT INTO People ?", people);
```

Você não coloca o marcador variável (`?`) entre colchetes angulares duplos (`<<...>>`) ao passar uma lista. Nas instruções manuais do PartiQL, colchetes angulares duplos denotam uma coleção não ordenada conhecida como *bolsa*.

### Como atualizar documentos
<a name="cookbook-nodejs.crud.updating"></a>

Os exemplos de código a seguir usam tipos de dados nativos.

------
#### [ JavaScript ]

```
(async function() {
    await qldbDriver.executeLambda(async (txn) => {
        await txn.execute('UPDATE Person SET FirstName = ? WHERE GovId = ?', 'John', 'TOYENC486FH');
    });
}());
```

------
#### [ TypeScript ]

```
(async function(): Promise<void> {
    await qldbDriver.executeLambda(async (txn: TransactionExecutor) => {
        await txn.execute('UPDATE Person SET FirstName = ? WHERE GovId = ?', 'John', 'TOYENC486FH');
    });
}());
```

------

O exemplo de código a seguir usa os tipos de dados Ion.

------
#### [ JavaScript ]

```
(async function() {
    await qldbDriver.executeLambda(async (txn) => {
        const firstName = ionjs.load("John");
        const govId = ionjs.load("TOYENC486FH");

        await txn.execute('UPDATE Person SET FirstName = ? WHERE GovId = ?', firstName, govId);
    });
}());
```

------
#### [ TypeScript ]

```
(async function(): Promise<void> {
    await qldbDriver.executeLambda(async (txn: TransactionExecutor) => {
        const firstName: dom.Value = load("John");
        const govId: dom.Value = load("TOYENC486FH");

        await txn.execute('UPDATE Person SET FirstName = ? WHERE GovId = ?', firstName, govId);
    });
}());
```

------

**nota**  
Neste exemplo, recomendamos ter um índice no campo `GovId` para otimizar o desempenho. Sem um índice em `GovId`, as instruções podem ter mais latência e também podem levar a exceções de conflitos de OCC ou a tempos limite de transação.

### Como excluir documentos
<a name="cookbook-nodejs.crud.deleting"></a>

Os exemplos de código a seguir usam tipos de dados nativos.

------
#### [ JavaScript ]

```
(async function() {
    await qldbDriver.executeLambda(async (txn) => {
        await txn.execute('DELETE FROM Person WHERE GovId = ?', 'TOYENC486FH');
    });
}());
```

------
#### [ TypeScript ]

```
(async function(): Promise<void> {
    await qldbDriver.executeLambda(async (txn: TransactionExecutor) => {
        await txn.execute('DELETE FROM Person WHERE GovId = ?', 'TOYENC486FH');
    });
}());
```

------

O exemplo de código a seguir usa os tipos de dados Ion.

------
#### [ JavaScript ]

```
(async function() {
    await qldbDriver.executeLambda(async (txn) => {
        const govId = ionjs.load("TOYENC486FH");

        await txn.execute('DELETE FROM Person WHERE GovId = ?', govId);
    });
}());
```

------
#### [ TypeScript ]

```
(async function(): Promise<void> {
    await qldbDriver.executeLambda(async (txn: TransactionExecutor) => {
        const govId: dom.Value = load("TOYENC486FH");

        await txn.execute('DELETE FROM Person WHERE GovId = ?', govId);
    });
}());
```

------

**nota**  
Neste exemplo, recomendamos ter um índice no campo `GovId` para otimizar o desempenho. Sem um índice em `GovId`, as instruções podem ter mais latência e também podem levar a exceções de conflitos de OCC ou a tempos limite de transação.

### Como executar várias instruções em uma transação
<a name="cookbook-nodejs.crud.multi-statement"></a>

------
#### [ TypeScript ]

```
// This code snippet is intentionally trivial. In reality you wouldn't do this because you'd
// set your UPDATE to filter on vin and insured, and check if you updated something or not.
async function insureCar(driver: QldbDriver, vin: string): Promise<boolean> {

    return await driver.executeLambda(async (txn: TransactionExecutor) => {
        const results: dom.Value[] = (await txn.execute(
            "SELECT insured FROM Vehicles WHERE vin = ? AND insured = FALSE", vin)).getResultList();

        if (results.length > 0) {
            await txn.execute(
                "UPDATE Vehicles SET insured = TRUE WHERE vin = ?", vin);
            return true;
        }
        return false;
    });
};
```

------

### Lógica de novas tentativas
<a name="cookbook-nodejs.crud.retry-logic"></a>

O método `executeLambda` do driver tem um mecanismo de repetição integrado que repete a transação se ocorrer uma exceção que pode ser repetida (como tempos limite ou conflitos de OCC). O número máximo de tentativas de repetição e a estratégia de recuo são configuráveis.

O limite padrão de repetição é`4`, e a estratégia de recuo padrão é [defaultBackoffFunction](https://amazon-qldb-docs.s3.amazonaws.com/drivers/nodejs/2.2.0/modules/_src_retry_defaultretryconfig_.html#defaultretryconfig)com uma base de `10` milissegundos. Você pode definir a configuração de repetição por instância de driver e também por transação usando uma instância de [RetryConfig](https://amazon-qldb-docs.s3.amazonaws.com/drivers/nodejs/2.2.0/classes/_src_retry_retryconfig_.retryconfig.html).

O exemplo de código a seguir especifica a lógica de repetição com um limite de repetição personalizado e uma estratégia de recuo personalizada para uma instância do driver.

------
#### [ JavaScript ]

```
var qldb = require('amazon-qldb-driver-nodejs');

// Configuring retry limit to 2
const retryConfig = new qldb.RetryConfig(2);
const qldbDriver = new qldb.QldbDriver("test-ledger", undefined, undefined, retryConfig);

// Configuring a custom backoff which increases delay by 1s for each attempt.
const customBackoff = (retryAttempt, error, transactionId) => {
    return 1000 * retryAttempt;
};

const retryConfigCustomBackoff = new qldb.RetryConfig(2, customBackoff);
const qldbDriverCustomBackoff = new qldb.QldbDriver("test-ledger", undefined, undefined, retryConfigCustomBackoff);
```

------
#### [ TypeScript ]

```
import { BackoffFunction, QldbDriver, RetryConfig } from "amazon-qldb-driver-nodejs"

// Configuring retry limit to 2
const retryConfig: RetryConfig = new RetryConfig(2);
const qldbDriver: QldbDriver = new QldbDriver("test-ledger", undefined, undefined, retryConfig);

// Configuring a custom backoff which increases delay by 1s for each attempt.
const customBackoff: BackoffFunction = (retryAttempt: number, error: Error, transactionId: string) => {
    return 1000 * retryAttempt;
};

const retryConfigCustomBackoff: RetryConfig = new RetryConfig(2, customBackoff);
const qldbDriverCustomBackoff: QldbDriver = new QldbDriver("test-ledger", undefined, undefined, retryConfigCustomBackoff);
```

------

O exemplo de código a seguir especifica a lógica de repetição com um limite de repetição personalizado e uma estratégia de recuo personalizada para uma instância do lambda. Essa configuração para `executeLambda` substitui a lógica de repetição definida para a instância do driver.

------
#### [ JavaScript ]

```
var qldb = require('amazon-qldb-driver-nodejs');

// Configuring retry limit to 2
const retryConfig1 = new qldb.RetryConfig(2);
const qldbDriver = new qldb.QldbDriver("test-ledger", undefined, undefined, retryConfig1);

// Configuring a custom backoff which increases delay by 1s for each attempt.
const customBackoff = (retryAttempt, error, transactionId) => {
    return 1000 * retryAttempt;
};

const retryConfig2 = new qldb.RetryConfig(2, customBackoff);

// The config `retryConfig1` will be overridden by `retryConfig2`
(async function() {
    await qldbDriver.executeLambda(async (txn) => {
        await txn.execute('CREATE TABLE Person');
    }, retryConfig2);
}());
```

------
#### [ TypeScript ]

```
import { BackoffFunction, QldbDriver, RetryConfig, TransactionExecutor } from "amazon-qldb-driver-nodejs"

// Configuring retry limit to 2
const retryConfig1: RetryConfig = new RetryConfig(2);
const qldbDriver: QldbDriver = new QldbDriver("test-ledger", undefined, undefined, retryConfig1);

// Configuring a custom backoff which increases delay by 1s for each attempt.
const customBackoff: BackoffFunction = (retryAttempt: number, error: Error, transactionId: string) => {
    return 1000 * retryAttempt;
};

const retryConfig2: RetryConfig = new RetryConfig(2, customBackoff);

// The config `retryConfig1` will be overridden by `retryConfig2`
(async function(): Promise<void> {
    await qldbDriver.executeLambda(async (txn: TransactionExecutor) => {
        await txn.execute('CREATE TABLE Person');
    }, retryConfig2);
}());
```

------

### Implementação de restrições de exclusividade
<a name="cookbook-nodejs.crud.uniqueness-constraints"></a>

O QLDB não oferece suporte a índices exclusivos, mas você pode implementar esse comportamento em seu aplicativo.

Suponha que você queira implementar uma restrição de exclusividade no campo `GovId` da tabela `Person`. Para fazer isso, você pode escrever uma transação que faça o seguinte:

1. Afirme que a tabela não tem documentos existentes com um `GovId` especificado.

1. Insira o documento se a afirmação for aprovada.

Se uma transação concorrente passar simultaneamente pela declaração, somente uma das transações será confirmada com sucesso. A outra transação falhará com uma exceção de conflito de OCC.

O exemplo de código a seguir mostra como implementar essa lógica de restrição de exclusividade.

------
#### [ JavaScript ]

```
const govId = 'TOYENC486FH';
const document = {
    'FirstName': 'Brent',
    'GovId': 'TOYENC486FH',
};
(async function() {
    await qldbDriver.executeLambda(async (txn) => {
        // Check if doc with GovId = govId exists
        const results = (await txn.execute('SELECT * FROM Person WHERE GovId = ?', govId)).getResultList();
        // Insert the document after ensuring it doesn't already exist
        if (results.length == 0) {
            await txn.execute('INSERT INTO Person ?', document);
        }
    });
})();
```

------
#### [ TypeScript ]

```
const govId: string = 'TOYENC486FH';
const document: Record<string, string> = {
    'FirstName': 'Brent',
    'GovId': 'TOYENC486FH',
};
(async function(): Promise<void> {
    await qldbDriver.executeLambda(async (txn: TransactionExecutor) => {
        // Check if doc with GovId = govId exists
        const results: dom.Value[] = (await txn.execute('SELECT * FROM Person WHERE GovId = ?', govId)).getResultList();
        // Insert the document after ensuring it doesn't already exist
        if (results.length == 0) {
            await txn.execute('INSERT INTO Person ?', document);
        }
    });
})();
```

------

**nota**  
Neste exemplo, recomendamos ter um índice no campo `GovId` para otimizar o desempenho. Sem um índice em `GovId`, as instruções podem ter mais latência e também podem levar a exceções de conflitos de OCC ou a tempos limite de transação.

## Como trabalhar com o Amazon Ion
<a name="cookbook-nodejs.ion"></a>

As seções a seguir mostram como usar o módulo Amazon Ion para processar dados do Ion.

**Contents**
+ [Importar o módulo Ion](#cookbook-nodejs.ion.import)
+ [Criação de tipos de Ion](#cookbook-nodejs.ion.creating-types)
+ [Obter um despejo de binário Ion](#cookbook-nodejs.ion.getting-binary)
+ [Obter um despejo de texto Ion](#cookbook-nodejs.ion.getting-text)

### Importar o módulo Ion
<a name="cookbook-nodejs.ion.import"></a>

------
#### [ JavaScript ]

```
var ionjs = require('ion-js');
```

------
#### [ TypeScript ]

```
import { dom, dumpBinary, dumpText, load } from "ion-js";
```

------

### Criação de tipos de Ion
<a name="cookbook-nodejs.ion.creating-types"></a>

O exemplo de código a seguir cria um objeto Ion a partir do texto Ion.

------
#### [ JavaScript ]

```
const ionText  = '{GovId: "TOYENC486FH", FirstName: "Brent"}';
const ionObj = ionjs.load(ionText);

console.log(ionObj.get('GovId')); // prints [String: 'TOYENC486FH']
console.log(ionObj.get('FirstName')); // prints [String: 'Brent']
```

------
#### [ TypeScript ]

```
const ionText: string = '{GovId: "TOYENC486FH", FirstName: "Brent"}';
const ionObj: dom.Value = load(ionText);

console.log(ionObj.get('GovId')); // prints [String: 'TOYENC486FH']
console.log(ionObj.get('FirstName')); // prints [String: 'Brent']
```

------

O exemplo de código a seguir cria um objeto Ion a partir de um dicionário Node.js.

------
#### [ JavaScript ]

```
const aDict = {
    'GovId': 'TOYENC486FH',
    'FirstName': 'Brent'
};
const ionObj = ionjs.load(ionjs.dumpBinary(aDict));
console.log(ionObj.get('GovId')); // prints [String: 'TOYENC486FH']
console.log(ionObj.get('FirstName')); // prints [String: 'Brent']
```

------
#### [ TypeScript ]

```
const aDict: Record<string, string> = {
    'GovId': 'TOYENC486FH',
    'FirstName': 'Brent'
};
const ionObj: dom.Value = load(dumpBinary(aDict));
console.log(ionObj.get('GovId')); // prints [String: 'TOYENC486FH']
console.log(ionObj.get('FirstName')); // prints [String: 'Brent']
```

------

### Obter um despejo de binário Ion
<a name="cookbook-nodejs.ion.getting-binary"></a>

------
#### [ JavaScript ]

```
// ionObj is an Ion struct
console.log(ionjs.dumpBinary(ionObj).toString()); // prints 224,1,0,234,238,151,129,131,222,147,135,190,144,133,71,111,118,73,100,137,70,105,114,115,116,78,97,109,101,222,148,138,139,84,79,89,69,78,67,52,56,54,70,72,139,133,66,114,101,110,116
```

------
#### [ TypeScript ]

```
// ionObj is an Ion struct
console.log(dumpBinary(ionObj).toString()); // prints 224,1,0,234,238,151,129,131,222,147,135,190,144,133,71,111,118,73,100,137,70,105,114,115,116,78,97,109,101,222,148,138,139,84,79,89,69,78,67,52,56,54,70,72,139,133,66,114,101,110,116
```

------

### Obter um despejo de texto Ion
<a name="cookbook-nodejs.ion.getting-text"></a>

------
#### [ JavaScript ]

```
// ionObj is an Ion struct
console.log(ionjs.dumpText(ionObj)); // prints {GovId:"TOYENC486FH",FirstName:"Brent"}
```

------
#### [ TypeScript ]

```
// ionObj is an Ion struct
console.log(dumpText(ionObj)); // prints {GovId:"TOYENC486FH",FirstName:"Brent"}
```

------

Para obter mais informações sobre o Ion, consulte a [documentação do Amazon Ion](http://amzn.github.io/ion-docs/) em GitHub. Para obter mais exemplos de código sobre como trabalhar com o Ion no QLDB, consulte [Como trabalhar com tipos de dados do Amazon Ion no Amazon QLDB](driver-working-with-ion.md).