MongoDB - Updates Complexos
Tags: mongodb, beginners, braziliandevs
Published: 2022-08-03 19:55:11

## Tabela de Conteúdos

- [Modificadores de Atualizações em Arrays](#modificadores-de-atualizações-em-arrays)
- [Operador `$push`](#operador-push)
- [Operador `$pop`](#operador-pop)
- [Operador `pull`](#operador-pull)
- [Operador `$addToSet`](#operador-addtoset)
- [Filtros em Arrays](#filtros-em-arrays)
- [Links Úteis](#links-úteis)

---

## Modificadores de Atualizações em Arrays

### O que são?

Modificadores de Atualizações em Arrays é uma tradução livre de _Update Operator Modifiers_, que nada mais são do que operadores que permitem a modificação do comportamento das atualizações em arrays internos de Documentos, possibilitando a ordenação, por exemplo.

### Onde/Quando utilizar?

Como visto em sua definição logo acima, esses operadores interagem diretamente com arrays, logo devemos utilizá-los somente em interações onde os campos sejam desse tipo.

Lembrando que esses operadores, além de estarem restritos aos campos do tipo array, também só poderão ser utilizados em operações de atualização.

### Quais são?

De acordo com a [documentação oficial](https://www.mongodb.com/docs/manual/reference/operator/update-array/#update-operator-modifiers), existem quatro modificadores, esses que serão abordados logo abaixo.

São eles: `$each`; `$position`; `$slice` e `$sort`.

### Sintaxe

Apesar de similares, cada _Update Operator Modifiers_ possui uma peculiaridade em sua sintaxe, então iremos explicá-los individualmente.

__`$each`__

- __Função__: permite a inserção de múltiplos valores em um campo do tipo array. _(funciona somente com os operadores `$push` e `$addToSet`)_

- __Sintaxe__: deve ser declarado após o campo a sofrer modificação e recebe um array com os valores a serem inseridos.

``` bash
{ <operador de atualização>: <campo>: { $each: [<valor 1>, <valor 2>, <valor 3>] } }
```

``` bash
{ $push: tasks: { $each: ["study", "go to the gym", "read"] } }
```

<br/>

<small>[voltar ao topo](#tabela-de-conteúdos)</small>

__`$position`__

- __Função__: permite a inserção de um, ou mais valores em uma posição específica do array. _(funciona somente com o operador `$push`)_

- __Sintaxe__: é necessário o uso do `$each` previamente, após isso declaramos o `$position` e dizemos a partir de qual posição os novos valores serão inseridos.

``` bash
{ $push: <campo>: { $each: [<valor 1>, <valor 2>, <valor 3>], $position: <index> } }
```

``` bash
{ $push: tasks: { $each: ["study", "go to the gym", "read"], $position: 2 } }
```

<br/>

<small>[voltar ao topo](#tabela-de-conteúdos)</small>

__`$slice`__

- __Função__: limita a inserção de novos valores. _(funciona somente com o operador `$push`)_

- __Sintaxe__: é necessário o uso do `$each` previamente, após isso declaramos o `$slice` e definimos qual o número máximo de valores a serem adicionados.

``` bash
{ $push: <campo>: { $each: [<valor 1>, <valor 2>, <valor 3>], $slice: <index> } }
```

``` bash
{ $push: tasks: { $each: ["study", "go to the gym", "read"], $slice: 2 } }
# irá inserir somente o "study" e o "go to the gym"
```

<br/>

<small>[voltar ao topo](#tabela-de-conteúdos)</small>

__`$sort`__

- __Função__: ordena todos os valores contidos no array, bem como os que serão adicionados. _(funciona somente com o operador `$push`)_

- __Sintaxe__: é necessário o uso do `$each` previamente, após isso declaramos o `$sort` e definimos por qual campo será feita a ordenação, bem como o tipo de ordenação _(crescente ou decrescente)_.

``` bash
{ $push: <campo>: { $each: [<valor 1>, <valor 2>], $sort: { <campo>: <tipo de ordenação> } } }
```

``` bash
{ $push: products: { $each: [{ name: "doll", qty: 5 }, { name:  "lego", qty: 2 }], $sort: { qty: 1 } } }
# no caso de não ser um objeto basta definir o tipo de ordenação diretamente => $sort: 1
```

<br/>

<small>[voltar ao topo](#tabela-de-conteúdos)</small>

---

## Operador `$push`

### O que é?

É um operador que lida diretamente com campos do tipo array, permitindo a adição de novos valores sem a necessidade de recriar o campo do zero.

### Sintaxe

Há duas formas de se utilizar o operador `$push`, podemos adicionar apenas um item ao final do array, ou adicionar vários itens de uma única vez, além de conseguirmos alterar outros comportamentos, como ordenação automática.

Para o primeiros caso, basta invocarmos o `$push`, declararmos o campo a sofrer a adição e por fim definir o item a ser adicionado.

Já nos outros casos é obrigatório o uso do operador `$each`, que além de permitir a inserção de múltiplos valores, também abre a possibilidade de alterarmos mais comportamentos.

``` bash
{ $push: { <campo>: <novo item> } }
{ $push: { <campo>: { $each: [<novos itens>], <outras configurações> } } }
```

``` bash
{ $push: { products: { name: "computer", price: 2499.99 } } }
{ $push: { products: $each: [{ name: "computer", price: 2499.99 }, { name: "mouse", price: 499.99 }] } }
```

<br/>

<small>[voltar ao topo](#tabela-de-conteúdos)</small>

---

## Operador `$pop`

### O que é?

É um operador de deleção, ele poderá excluir o primeiro ou o último elemento de um array.

### Sintaxe

Para deletarmos o primeiro ou o último item de um array basta invocarmos o método `$pop`, em seguida definimos o campo que contém o array a sofrer a deleção e por fim dizemos qual elemento a ser excluído _(primeiro ou último)_.

``` bash
{ $pop: { <campo>: <item a ser excluído> } }
```

``` bash
{ $pop: { products: 1 } }
# 1 => exclui o último
# -1 => exclui o primeiro
```

<br/>

<small>[voltar ao topo](#tabela-de-conteúdos)</small>

---

## Operador `$pull`

### O que é?

É um operador que permite a deleção de itens em um campo do tipo array através de condições, dessa forma todos os itens que se encaixam nas condições definidas são excluídos.

### Sintaxe

O primeiro passo é invocarmos o `$pull`, após isso definimos o campo a sofrer as deleções e por fim dizemos as condições a serem cumpridas para que um elemento seja deletado.

``` bash
{ $pull: { <campo>: <query de deleção> } }  # query é equivalente a "conjunto de condições"
```

``` bash
{ $pull: { products: { price: { $gt: 400.00 } } } }
```

<br/>

<small>[voltar ao topo](#tabela-de-conteúdos)</small>

---

## Operador `$addToSet`

### O que é?

Esse operador funciona de forma similar ao `$push`, porém além de adicionar novos valores a um campo do tipo array, o `$addToSet` também realiza uma verificação para evitar valores duplicados, ou seja, o novo valor somente será inserido se ele for único.

Vale ressaltar que esse o processo de validar Documentos duplicados é mais _"sensível"_ ao erro, isso porque o operador irá considerar como duplicata apenas os Documentos que forem __EXATAMENTE IGUAIS__.

### Sintaxe

Assim como seu funcionamento, sua sintaxe também é extremamente similar a do operador `$push`, o que significa que podemos adicionar um item, ou mais itens de uma única vez utilizando o `$each`, porém o `$addToSet` não aceita outras opções como o `$sort`.

Para adicionarmos um item basta invocarmos o operador `$addToSet`, seguido do campo a sofrer a adição e então definimos o novo valor a ser adicionado.

Já para adicionarmos múltiplos itens, invocamos o operador `$addToSet`, seguido do campo a sofrer a adição, depois declaramos o operador `$each` e por fim, dentro de um array, definimos os valores a serem adicionados.

``` bash
{ $addToSet: { <campo>: <valor> } }
{ $addToSet: { <campo>: { $each: [<valor1>, <valor2>, <valor3>] } }
```

``` bash
{ $addToSet: { email: gabriel@gabriel.com } }
{ $addToSet: { email: { $each: [gabriel@gabriel.com, daniela@daniela.com, fran@fran.com] } }
```

Obs: _"Caso exista um valor duplicado dentro do array que estamos realizando a adição, o MongoDB executará a ação sem levantar nenhum erro, porém o valor duplicado não é adicionado, apenas mantêm-se o valor pré-existente"_.

<br/>

<small>[voltar ao topo](#tabela-de-conteúdos)</small>

---

## Filtros em Arrays

### O que são?

São formas pelas quais podemos selecionar um único valor dentro de um array de forma dinâmica, fazendo um paralelo com o JS, seria equivalente a HOF `.find()`.

### Sintaxe

A sintaxe desses filtros, apesar de simples, tem sua peculiaridade, isso porque ela funciona de forma similar a interpolação do [mysql2](https://dev.to/gabrielhsilvestre/model-uma-breve-introducao-4gch/#query-din%C3%A2mica) com node.

Utilizamos os filtros de array dentro operações de atualização, através do operador [`$[<identifier>]`](https://www.mongodb.com/docs/manual/reference/operator/update/positional-filtered/#up._S_%5B%3Cidentifier%3E%5D) definimos um nome genérico que será usado como referência na interpolação. Agora para realmente definirmos o valor a ser buscado, utilizamos a opção `arrayFilters`, passando todas as referências que criamos anteriormente e atribuindo um valor a elas.

``` bash
{ <operação de att>: { <campo>.$[<referência>]: <novo valor> } },
{ arrayFilters: [{ <referência>: <valor a ser buscado> }] }
```

``` bash
{ $set: { tasks.$[t].title: "study Node" } },
{ arrayFilters: [{ t.title: "study React" }] }

# o item com o "title" study React vai ter seu valor trocado para study Node
```

``` bash
# Por se tratar de um recurso mais complexo, irei exemplificar com o método de atualização completo
# A função continua sendo a mesma, trocar "study React" por "study Node"

db.user_tasks.updateOne(
  { _id: 1 },
  {
    $set: { tasks.$[T].title: "study Node" }
  },
  { arrayFilters: [{ T.title: "study React" }] }
)
```

<br/>

<small>[voltar ao topo](#tabela-de-conteúdos)</small>

---

## Links Úteis

- [Operadores de Atualização](https://www.mongodb.com/docs/manual/reference/operator/update-array/#update-operators)
- [Modificadores de Atualização](https://www.mongodb.com/docs/manual/reference/operator/update-array/#update-operator-modifiers)
- [Operador `$[<identifier>]`](https://www.mongodb.com/docs/manual/reference/operator/update/positional-filtered/)
- [Operador `$(update)`](https://www.mongodb.com/docs/manual/reference/operator/update/positional/)
- [Operador `$[]`](https://www.mongodb.com/docs/manual/reference/operator/update/positional-all/)
- [Operadores de Consulta](../Day-29.3/Operadores-Consulta.md)
- [Update Simples](../Day-29.4/Update-Simples.md)

<br/>

<small>[voltar ao topo](#tabela-de-conteúdos)</small>