# Object Store

O **Object Store** realiza operações para armazenar qualquer documento no *Object Store* da Digibee. É uma maneira rápida e fácil de salvar informações úteis do tipo JSON, que possui operações para auxiliar em diversos usos durante a criação de um *pipeline*.

## Parâmetros

Dê uma olhada nas opções de configuração do conector. Parâmetros suportados por [expressões *Double Braces*](https://docs.digibee.com/documentation/connectors-and-triggers/pt-br/double-braces/overview) estão marcados com `(DB)`.

<table data-full-width="true"><thead><tr><th>Parâmetro</th><th>Descrição</th><th>Valor padrão</th><th>Tipo de dado</th></tr></thead><tbody><tr><td><strong>Account</strong></td><td>Conta que será utilizada pelo conector. Este item não pode ser alterado.</td><td>Digibee Object Store Account</td><td>N/A</td></tr><tr><td><strong>Operation</strong></td><td>Operação que será executada dentro do <strong>Object Store</strong> - <em>Find by Object ID</em>, <em>Find By Query</em>, <em>Insert</em>, <em>Aggregate</em>, <em>Update By Object ID</em>, <em>Update By Query</em>, <em>Delete By Object ID</em>, <em>Delete By Query</em>, <em>Create Index</em>, <em>List Indexes</em> e <em>Drop Index</em>.</td><td><em>Find by Object ID</em></td><td><em>String</em></td></tr><tr><td><strong>Object Store Name</strong></td><td>Nome da coleção que será utilizada para gravar ou ler informações. Caso não exista, ela será criada automaticamente.</td><td>sales</td><td><em>String</em></td></tr><tr><td><strong>Expire After Seconds</strong> <code>(DB)</code></td><td>Determina o número de segundos após os quais um documento do <strong>Object Store</strong> expira.</td><td>0</td><td>Inteiro</td></tr><tr><td><strong>Object ID</strong> <code>(DB)</code></td><td>Identificador do objeto que será armazenado ou buscado. Pode ser um número ou um UUID. Este item suporta <em>Double Braces</em>.</td><td>1</td><td><em>String</em></td></tr><tr><td><strong>Limit</strong> <code>(DB)</code></td><td>Número máximo de objetos que serão retornados em uma busca. Este item suporta <em>Double Braces</em>.</td><td>0</td><td>Inteiro</td></tr><tr><td><strong>Skip</strong> <code>(DB)</code></td><td>Quantidade de objetos a serem pulados antes de retornar para a <em>query</em>. Este parâmetro é normalmente utilizado em conjunto com o parâmetro <strong>Limit</strong> para criar uma forma de paginação. Este item suporta <em>Double Braces.</em></td><td>0</td><td>Inteiro</td></tr><tr><td><strong>Sort</strong> <code>(DB)</code></td><td>Especificação das regras de ordenação da <em>query</em>.</td><td>N/A</td><td><em>String</em></td></tr><tr><td><strong>Query</strong> <code>(DB)</code></td><td>Este campo JSON para consulta é disponível somente se as operações <em>Find by Query</em>, <em>Aggregate</em>, <em>Update by Query</em>, <em>Delete by Query</em>, <em>Create Index</em> ou <em>Drop Index</em> estiverem selecionadas.</td><td>N/A</td><td><em>String</em></td></tr><tr><td><strong>Document</strong> <code>(DB)</code></td><td>Disponível somente se as operações <em>Insert, Update by Object ID</em> ou <em>Update by Query</em> estiverem selecionadas. Expressões <em>Double Braces</em> são permitidas.</td><td>N/A</td><td><em>String</em></td></tr><tr><td><strong>Unique Index</strong></td><td>Se a opção estiver ativada, será criado um <em>Object ID</em> que aceita apenas valores únicos; do contrário, um index não único será criado.</td><td><em>True</em></td><td>Booleano</td></tr><tr><td><strong>Isolated</strong></td><td>Se a opção estiver ativada, todas as queries serão delimitadas no escopo de execução.</td><td><em>False</em></td><td>Booleano</td></tr><tr><td><strong>Upsert</strong></td><td>Esta opção é disponível somente se as operações <em>Update By Object ID</em> ou <em>Update By Query</em> estiverem selecionadas. Quando ativado, o objeto informado para o conector será inserido na coleção caso ele não exista.</td><td><em>False</em></td><td>Booleano</td></tr><tr><td><strong>Fail On Error</strong></td><td>Se a opção estiver habilitada, a execução do <em>pipeline</em> com erro será interrompida; do contrário, a execução do <em>pipeline</em> continua, mas o resultado vai mostrar um valor falso para a propriedade "<em>success</em>".</td><td><em>False</em></td><td>Booleano</td></tr></tbody></table>

## Boas práticas de utilização <a href="#h_1c70874a1a" id="h_1c70874a1a"></a>

O **Object Store** é uma base de dados (*NoSQL*) auxiliar para integrações. Sua utilização confere mais agilidade e praticidade no desenvolvimento de integrações. Para exemplificar a aplicabilidade deste conector, listamos as seguintes boas práticas de utilização:

* O **Object Store** desempenha a função de uma base de dados intermediária, isto é, para intermediação de informações entre fluxos de uma integração. Sendo assim, ele deve ser utilizado unicamente para armazenamento de informações relevantes para a integração em questão.
* O **Object Store** é um banco de dados temporário. Uma vez utilizado para intermediar informações relevantes para o fluxo de integração, dados antigos e dispensáveis devem ser removidos regularmente do banco de dados. Você pode removê-los manualmente ou criar um *index* com um mecanismo de TTL (*Time to live*) para expirar automaticamente os dados antigos.
* Por se tratar de uma base auxiliar, o conector **Object Store** não deve ser utilizado como uma base de dados permanente, mas sim de maneira pontual, com o objetivo de apoiar o usuário no desenvolvimento das integrações.
* Todo e qualquer dado é armazenado com o máximo de segurança dentro da Digibee Integration Platform. Ainda assim, recomendamos que dados sensíveis armazenados no **Object Store** sejam criptografados. Para isso, utilize nossos conectores de criptografia disponíveis no canvas.

## Fluxo de mensagens <a href="#fluxo-de-mensagens" id="fluxo-de-mensagens"></a>

### Entrada <a href="#entrada" id="entrada"></a>

Para esse conector específico, o único padrão de mensagem de entrada obrigatória é o formato JSON aplicado ao objeto. O parâmetro de entrada pode utilizar a sintaxe de *Double Braces* para enviar a mensagem recebida para o conector.

### Saída <a href="#sada" id="sada"></a>

* **Insert**

```json
{
    "data": [],
    "updateCount": 1
}
```

* **Find**

```json
{
   "data": [
       {
           "name": "Galaxy s20",
           "uuid": "123",
           "_oId": "1"
       }
   ],
   "rowCount": 1
}
```

* **Update**

```json
{
    "data": [],
    "updateCount": 1
}
```

* **Delete**

```json
{
    "data": [],
    "updateCount": 1
}
```

* **Aggregate**

```json
{
    "data": [],
    "rowCount": 0
}
```

## Object Store em ação <a href="#object-store-em-ao" id="object-store-em-ao"></a>

Acima foram demonstrados alguns exemplos de saída de cada operação. Veja abaixo mais aplicações que demonstram a configuração correta para que se obtenha determinado resultado:

### **Inserir diversos itens de uma única vez em uma coleção**

Ao enviar um *array* de objetos no campo *query*, o conector insere cada item de forma separada dentro da coleção selecionada.

Observe como configurar o conector com os parâmetros **Operation** (*Insert*), **Unique Index** (*False*) e **Query:**

```json
[
   {
       "id": 1,
       "name": "Galaxy s20",
       "price": 5000
   },
   {
       "id": 2,
       "name": "Samsung 4k 55\"",
       "price": 5000
   },
   {
       "id": 3,
       "name": "Galaxy A10",
       "price": 699
   },
   {
       "id": 4,
       "name": "Galaxy A51",
       "price": 1620
   }
]
```

#### **Saída**

```json
{
    "data": [],
    "updateCount": 4
}
```

{% hint style="info" %}
A inserção de múltiplos objetos de uma só vez é permitida apenas em coleções criadas com **Unique Index** (*False*). A propriedade **Unique Index** é definida na criação da coleção. Depois que o *index* é criado, não é possível alterar a propriedade.
{% endhint %}

### **Encontrar itens a partir de uma determinada query**

Como exemplo, considere um **Object Store** que já possui itens cadastrados do tipo produto e que tem as características de nome e preço.

Observe como configurar o conector com os parâmetros **Operation** *(Find By Query)* e **Query:**

```json
{
    "product.price": { $gt: 2000 }
}
```

#### **Saída**

```json
{
   "data": [
       {
           "product": {
               "id": 1,
               "name": "Galaxy s20",
               "price": 5000
           },
           "_oId": "1"
       },
       {
           "product": {
               "id": 2,
               "name": "Samsung 4k 55\"",
               "price": 5000
           },
           "_oId": "2"
       }
   ],
   "rowCount": 2
}
```

### **Encontrar todos os itens a partir de uma query**

Como exemplo, considere um **Object Store** que já possui itens cadastrados do tipo produto e que tem as características de nome e preço.

Observe como configurar o conector com os parâmetros **Operation** *(Find By Query),* **Limit** *(10)* e **Query**:

```json
{}
```

#### **Saída**

```json
{
   "data": [
       {
           "product": {
               "id": 1,
               "name": "Galaxy s20",
               "price": 5000
           },
           "_oId": "1"
       },
       {
           "product": {
               "id": 2,
               "name": "Samsung 4k 55\"",
               "price": 5000
           },
           "_oId": "2"
       },
       {
           "product": {
               "id": 3,
               "name": "Galaxy A10",
               "price": 699
           },
           "_oId": "3"
       },
       {
           "product": {
               "id": 4,
               "name": "Galaxy A51",
               "price": 1620
           },
           "_oId": "4"
       }
   ],
   "rowCount": 4
}
```

Nesse cenário específico, o parâmetro **Limit** foi configurado para que não haja uma sobrecarga desnecessária ao retornar os objetos de um **Object Store**. Caso a opção não seja configurada dessa forma, poderá ocorrer um erro de "*Out Of Memory"* dentro do *pipeline.* Da maneira indicada, existe controle sobre quantos objetos são visualizados na resposta.

### **Atualizar um item a partir de um ID específico**

Como exemplo, considere um **Object Store** que já possui itens cadastrados do tipo produto e que possui as características de nome e preço.

Observe como configurar o conector com os parâmetros **Operation** *(Update By Object ID)*, **Object ID** (3) e **Document***:*

```json
{
   $set: {
       "product": {
         "id": 3,
         "name": "Galaxy A10",
         "price": 605
       }
   }
}
```

#### **Saída**

```json
{
    "data": [],
    "updateCount": 1
}
```

Nesse cenário específico, é possível ver que a saída é apenas um objeto identificando a realização de uma atualização. Para visualizar se o objeto foi devidamente atualizado, repita o cenário da busca por ID.

{% hint style="info" %}
Se o conector **Object Store** estiver envolvido em atualizações, dentro de um conector de iterações *(*[**For Each**](https://docs.digibee.com/documentation/connectors-and-triggers/pt-br/connectors/logic/for-each)*,* [**Stream File Reader**](https://docs.digibee.com/documentation/connectors-and-triggers/pt-br/connectors/files/stream-file-reader), etc.) e realizando execuções paralelas, pode haver concorrência na atualização de registros caso as instruções de atualização de registros sejam exatamente iguais. Consequentemente, uma instrução retornará *"updateCount":1* e a outra *"updateCount": 0*. Isso acontece quando 2 registros exatamente iguais entram no *pool* de operação do **Object Store** e as instruções de atualização ou inserção (com o parâmetro **Upsert** habilitado) são executadas sequencialmente. A primeira instrução efetiva uma atualização e a segunda encontra o registro já persistido e verifica que não há nada a ser modificado, retornando que nenhuma ação foi necessária (*"updateCount": 0*).
{% endhint %}

### **Remover um item a partir de um ID específico**

Como exemplo, considere um **Object Store** que já possui itens cadastrados do tipo produto e que tem as características de nome e preço.

Observe como configurar o conector com os parâmetros **Operation** *(Delete By Object ID)* e **Object ID** *(*&#x34;*)*.

#### **Saída**

```json
{
    "data": [],
    "updateCount": 1
}
```

Nesse cenário específico, é possível ver que a saída é apenas um objeto identificando a realização de uma atualização. Para visualizar se o objeto foi devidamente removido, repita o cenário da busca por ID.

### **Agregação para cópia da coleção**

Como exemplo, considere um **Object Store** chamado *"product"* que já possui itens cadastrados do tipo produto e que tem as características de nome e preço. A partir disso, crie um novo **Object Store** chamado "*product-backup"*, copiando todos os itens da coleção mencionada acima.

Você deve receber um *array* de objetos contendo os *pipelines* de agregação da *query* no parâmetro **Document***.*

Observe como configurar o conector com os parâmetros **Operation** *(Aggregate)* e **Query**:

```json
[
   {
       $merge: {
           into: "product-backup",
           on: "_id",
           whenMatched: "replace",
           whenNotMatched: "insert"
       }
   }
]
```

Nesse cenário específico, a *query* foi configurada para substituir itens repetidos pelos novos na coleção.

#### **Saída**

```json
{
    "data": [],
    "rowCount": 0
}
```

Para verificar se a coleção foi devidamente criada com os itens propostos, repita o cenário da busca por todos os itens e informe a coleção nova.

### **Agregação para filtro de itens da coleção**

Você deve receber um *array* de objetos contendo os *pipelines* de agregação da *query* no parâmetro **Document***.*

Observe como configurar o conector com os parâmetros **Operation** *(Aggregate*) e **Query**:

```json
[
   {
       $match: {
           "product.price": {
               $gt: 3000
           }
       }
   },
   {
       $group: {
           _id: null,
           count: {
               $sum: 1
           }
       }
   }
]
```

Nesse cenário específico, a *query* foi configurada para buscar os produtos que possuem determinado valor e apenas apresentar a soma deles.

#### **Saída**

```json
{
    "data": [
        {
            "count": 2
        }
    ],
    "rowCount": 0
}
```

### Criar um index com tempo de expiração

Com o **Object Store** é possível criar um *index* com um atributo TTL (*Time to live*), com o qual você pode definir uma estratégia de expiração para os documentos. Esse comportamento é controlado no parâmetro **Expire after seconds**. Aqui estão alguns exemplos de como você pode criar *indexes* com estratégias de expiração:

#### Criar um index com TTL constante

Veja um exemplo para a configuração dos parâmetros **Expire after seconds** e **Query**:

<figure><img src="https://content.gitbook.com/content/SKBJ6ZiEWBU93x170HH4/blobs/Jv8ZY98H9jacvarvsaCA/image1.png" alt=""><figcaption></figcaption></figure>

O nome do campo deve corresponder ao atributo de data do seu documento, que controlará o tempo de vida do objeto. Além disso, todos os documentos com esse campo são automaticamente excluídos após o número de segundos especificado no parâmetro **Expire after seconds**.

**Output**

```json
{
    "data": "expiresAt_1",
    "rowCount": 0
}
```

#### Criar um index com datas personalizadas

Veja um exemplo para a configuração dos parâmetros **Expire after seconds** e **Query**:

<figure><img src="https://content.gitbook.com/content/SKBJ6ZiEWBU93x170HH4/blobs/BEveFN94W6LRuFWcGpm4/image2.png" alt=""><figcaption></figcaption></figure>

O nome do campo deve corresponder ao atributo de data do seu documento, que controlará o tempo de vida do objeto. Você também deve configurar o parâmetro **Expire after seconds** para 0.

Nesse cenário, a expiração é definida com a data e hora definidas no valor do campo correspondente no parâmetro **Query**.

{% hint style="info" %}
Ao inserir novos documentos, certifique-se de que o campo que você configurou no *index* seja criado com um valor de data.
{% endhint %}

```json
{
    "id": 1,
    "name": "Galaxy s20",
    "price": 5000,
    "expiresAt": new Date()
}
```

{% hint style="info" %}
O *TTL index* não garante que os dados expirados sejam excluídos imediatamente após a expiração. Pode haver um atraso entre o momento em que um documento expira e o momento em que o **Object Store** remove o documento do banco de dados. Isso acontece porque a tarefa em segundo plano que remove documentos expirados é executada a cada 60 segundos.
{% endhint %}

### Listar todos os indexes

Essa operação deve listar todos os *indexes* que o usuário criou em um **Object Store**.

#### Output

```json
{
  "data": [
    {
      "v": 2,
      "key": {
        "expiresAt": 1
      },
      "name": "expiresAt_1",
      "expireAfterSeconds": 0
    }
  ],
  "rowCount": 1
}
```

### Fazer o drop um index existente

Nessa operação, é possível fazer o *drop* um index previamente criado pelo cliente.

Veja como configurar o conector com o parâmetro **Drop Index Operation** e **Query**:

```json
{
    "expiresAt": 1
}
```

#### Output

```json
{ 
    "data": "expiresAt_1", 
    "rowCount": 0
}
```

## Tecnologia <a href="#tecnologia" id="tecnologia"></a>

O **Object Store** utiliza operadores de busca e agregação de objetos semelhantes à sintaxe do MongoDB. [Consulte a documentação externa do MongoDB para saber mais.](https://www.mongodb.com/docs/manual/reference/operator/)

{% hint style="info" %}
Os dados do **Object Store** são isolados entre os ambientes. Entretanto, os dados do ambiente de **Test** compartilham o mesmo ambiente que os dados do [**Painel de execução**](https://app.gitbook.com/s/cO0A6g1dOsu8BiHYqO67/development-cycle/build-overview/canvas/execution-panel).
{% endhint %}
