Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Desenvolvedor do MongoDB
Central de desenvolvedor do MongoDBchevron-right
Produtoschevron-right
MongoDBchevron-right

Atualizar elementos de array em um documento com operadores posicionais MQL

Nic Raboy6 min read • Published Jan 28, 2022 • Updated Feb 03, 2023
MongoDB
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
O MongoDB oferece uma linguagem de consulta avançada que é ótima para operações de criação, leitura, atualização e exclusão, bem como pipelines complexos de agregação de vários estágios. Há muitas maneiras de modelar seus dados no MongoDB e, independentemente de sua aparência, a MongoDB Query Language (MQL) ajuda você.
Uma das funcionalidades menos reconhecidas, mas extremamente valiosas do MQL, está nos operadores posicionais que você encontraria em uma operação de atualização.
Digamos que você tenha um documento e, dentro desse documento, tenha uma array de objetos. Você precisa atualizar um ou mais desses objetos na array, mas não deseja substituir a array ou anexar a ela. É aqui que um operador posicional pode ser valioso.
Neste tutorial, vamos ver alguns exemplos que se beneficiariam de um operador posicional no MongoDB.

Use o operador $ para atualizar a primeira correspondência em uma array

Vamos usar o exemplo de que temos uma array em cada um de nossos documentos e queremos atualizar apenas a primeira correspondência dentro dessa array, mesmo que haja potencial para várias correspondências.
Para fazer isso, provavelmente queremos usar o operador$, que atua como um espaço reservado para atualizar o primeiro elemento correspondente.
Para este exemplo, vamos usar um jogo eletrônico do tipo Pokemon. Dê uma olhada no seguinte documento do MongoDB:
1{
2 "_id": "red",
3 "pokemon": [
4 {
5 "number": 6,
6 "name": "Charizard"
7 }
8 {
9 "number": 25,
10 "name": "Pikachu",
11 },
12 {
13 "number": 0,
14 "name": "MissingNo"
15 }
16 ]
17}
Suponhamos que o documento acima represente as informações sobre o pokémon do jogo Pokémon Red. O documento não é um reflexo verdadeiro e está muito incompleto. No entanto, se você é Fã do jogo, provavelmente se lembrará do pokémon com falha chamado "MissingNo". Para criar uma história fictícia, vamos presumir que o desenvolvedor, em algum momento, queira dar um nome real a esse pokémon, mas se esqueceu.
Podemos atualizar esse elemento específico na array fazendo algo como o seguinte:
1db.pokemon_game.update(
2 { "pokemon.name": "MissingNo" },
3 {
4 "$set": {
5 "pokemon.$.name": "Agumon"
6 }
7 }
8);
No exemplo acima, estamos fazendo um filtro para documentos que têm um elemento de array com um camponame definido como MissingNo. Com o MongoDB, você não precisa especificar o índice da array em seu filtro para o operador update . Na etapa de manipulação, estamos usando o operador posicional$ para alterar a primeira ocorrência da correspondência no filtro. Sim, no meu exemplo, estou renomeando o pokémon "MissingNo" para o de um Digimon, que é uma marca totalmente diferente.
O novo documento ficaria assim:
1{
2 "_id": "red",
3 "pokemon": [
4 {
5 "number": 6,
6 "name": "Charizard"
7 }
8 {
9 "number": 25,
10 "name": "Pikachu",
11 },
12 {
13 "number": 0,
14 "name": "Agumon"
15 }
16 ]
17}
Se "MissingNo" aparecesse várias vezes na array, apenas a primeira ocorrência seria atualizada. Se "MissingNo" aparecesse várias vezes, mas os campos ao redor fossem diferentes, você poderia fazer a correspondência em vários campos usando o operador$elemMatch para restringir qual elemento específico deve ser atualizado.
Mais informações sobre o $ operador posicional podem ser encontradas na documentação.

Use o operador $[] para atualizar todos os elementos de array em um documento

Digamos que você tenha uma array em seu documento e precise atualizar todos os elementos dessa array usando uma única operação. Para fazer isso, podemos dar uma olhada no operador$[] que faz exatamente isso.
Usando o mesmo exemplo de videogame Pokémon, vamos imaginar que temos uma equipe de Pokémon e acabamos de terminar uma batalha no jogo. Os pontos de experiência ganhos na batalha precisam ser distribuídos para todos os Pokémon da sua equipe.
O documento que representa nossa equipe pode se parecer com o seguinte:
1{
2 "_id": "red",
3 "team": [
4 {
5 "number": 1,
6 "name": "Bulbasaur",
7 "xp": 5
8 },
9 {
10 "number": 25,
11 "name": "Pikachu",
12 "xp": 32
13 }
14 ]
15}
No final da partida, queremos garantir que cada pokémon da nossa equipe receba 10 experiência. Para fazer isso com o operador$[], podemos construir uma operaçãoupdate que se parece com o seguinte:
1db.pokemon_game.update(
2 { "_id": "red" },
3 {
4 "$inc": {
5 "team.$[].xp": 10
6 }
7 }
8);
No exemplo acima, usamos o modificador$inc para aumentar todos os campos xpdentro da arrayteam em um número constante. Para saber mais sobre o operador $inc , consulte adocumentação.
Nosso novo documento ficaria assim:
1[
2 {
3 "_id": "red",
4 "team": [
5 {
6 "number": 1,
7 "name": "Bulbasaur",
8 "xp": 15
9 },
10 {
11 "number": 25,
12 "name": "Pikachu",
13 "xp": 42
14 }
15 ]
16 }
17]
Embora seja útil para este exemplo, não fornecemos exatamente critérios para o caso de um de seus Pokémon não receber pontos de experiência. Se o seu Pokémon desmaiou, talvez ele não devesse receber o aumento.
Aprenderemos sobre filtros na próxima parte do tutorial.
Para saber mais sobre o operador $[], confira a documentação.

Use o operador $[<identifier>] para atualizar elementos que correspondam a uma condição de filtro

Vamos usar o exemplo de que temos vários elementos de array que queremos atualizar em uma única operação e não queremos nos preocupar com código excessivo do lado do cliente emparelhado com uma operação de substituição.
Para fazer isso, provavelmente queremos usar o operador$[<identifier>], que atua como um espaço reservado para atualizar todos os elementos que correspondem a uma condiçãoarrayFilters.
Para colocar as coisas em perspectiva, digamos que estamos lidando com cartas colecionáveis de Pokémon, em vez de videogames, e rastreando seus valores. Nossos documentos podem ter a seguinte aparência:
1db.pokemon_collection.insertMany(
2 [
3 {
4 _id: "nraboy",
5 cards: [
6 {
7 "name": "Charizard",
8 "set": "Base",
9 "variant": "1st Edition",
10 "value": 200000
11 },
12 {
13 "name": "Pikachu",
14 "set": "Base",
15 "variant": "Red Cheeks",
16 "value": 300
17 }
18 ]
19 },
20 {
21 _id: "mraboy",
22 cards: [
23 {
24 "name": "Pikachu",
25 "set": "Base",
26 "variant": "Red Cheeks",
27 "value": 300
28 },
29 {
30 "name": "Pikachu",
31 "set": "McDonalds 25th Anniversary Promo",
32 "variant": "Holo",
33 "value": 10
34 }
35 ]
36 }
37 ]
38);
É claro que o trecho acima não é um documento, mas uma operação para inserir dois documentos em alguma coleçãopokemon_collection no MongoDB. No cenário acima, cada documento representa uma coleção de cartões para um individual. A arraycards contém informações sobre o cartão na coleção, bem como o valor atual.
Em nosso exemplo, precisamos atualizar os preços dos cartões, mas não queremos fazer um número X de operações de atualização no banco de dados. Queremos fazer apenas uma única operação para atualizar os valores de cada um dos nossos cartões.
Pegue a seguinte query:
1db.pokemon_collection.update(
2 {},
3 {
4 "$set": {
5 "cards.$[elemX].value": 350,
6 "cards.$[elemY].value": 500000
7 }
8 },
9 {
10 "arrayFilters": [
11 {
12 "elemX.name": "Pikachu",
13 "elemX.set": "Base",
14 "elemX.variant": "Red Cheeks"
15 },
16 {
17 "elemY.name": "Charizard",
18 "elemY.set": "Base",
19 "elemY.variant": "1st Edition"
20 }
21 ],
22 "multi": true
23 }
24);
A operaçãoupdateacima é como qualquer outra, mas com uma etapa extra para o nosso operador posicional. O primeiro parâmetro, que é um objeto vazio, representa nossos critérios de correspondência. Como ele está vazio, estaremos atualizando todos os documentos da coleção.
O próximo parâmetro é a manipulação que queremos fazer em nossos documentos. Vamos ignorá-lo por enquanto e ver o arrayFilters no terceiro parâmetro.
Imagine que queremos atualizar o preço de dois cartões específicos que possam existir na coleção de pokémon de qualquer pessoa. Neste exemplo, queremos atualizar o preço dos cartões Pikachu e Chartizard. Se você é um filtro donos de coleções de cartas, você saberá que há muitas variações do cartão de Pikachu e Chartizard, então nos tornamos específicos em nossa array arrayFilters . Para cada objeto na array, os campos desses objetos representam uma condiçãoand. Então, para elemX, que não tem nenhuma convenção de nomenclatura específica, todos os três campos devem ser satisfeitos.
No exemplo acima, estamos utilizando elemX e elemY para representar dois filtros diferentes.
Let's Go back to the second parameter in the operation update. Se o filtroelemX retornar como verdadeiro porque houve correspondência com um item de matriz em um documento, o campo valuedesse objeto será definido com um novo valor. Da mesma forma, o mesmo poderia acontecer com o filtroelemY. Se um documento tiver uma matriz e um dos filtros nunca corresponder a um elemento dessa matriz, ele será ignorado.
Se analisarmos o nosso exemplo, os documentos agora seriam os seguintes:
1[
2 {
3 "_id": "nraboy",
4 "cards": [
5 {
6 "name": "Charizard",
7 "set": "Base",
8 "variant": "1st Edition",
9 "value": 500000
10 },
11 {
12 "name": "Pikachu",
13 "set": "Base",
14 "variant": "Red Cheeks",
15 "value": 350
16 }
17 ]
18 },
19 {
20 "_id": "mraboy",
21 "cards": [
22 {
23 "name": "Pikachu",
24 "set": "Base",
25 "variant": "Red Cheeks",
26 "value": 350
27 },
28 {
29 "name": "Pikachu",
30 "set": "McDonalds 25th Anniversary Promo",
31 "variant": "Holo",
32 "value": 10
33 }
34 ]
35 }
36]
Se qualquer array específica contiver várias correspondências para um dos critériosarrayFilter, todas as correspondências terão seu preço atualizado. Isso significa que, se eu tivesse, digamos, 100 cartões de Pikachu correspondentes em minha coleção de pokémon, todos os 100 agora teriam novos preços.
Mais informações sobre o operador $[<identifier>] podem ser encontradas na documentação.

Conclusão

Você acabou de ver como usar alguns dos operadores posicionais na linguagem de query do MongoDB (MQL). Esses operadores são úteis ao trabalhar com arrays, pois evitam que você tenha que fazer substituições completas na array ou manipulação estendida do lado do cliente.
Para saber mais sobre MQL, confira meu tutorial anterior intituladoGetting Started with Atlas and the MongoDB Query Language (MQL).
Se você tiver alguma dúvida, reserve um momento para visitar os MongoDB Community.

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Artigo

5 principais lições da Hacktoberfest 2020


Sep 23, 2022 | 8 min read
Tutorial

Segurança de tipo com Prisma e MongoDB


Aug 09, 2024 | 4 min read
Podcast

Dimensionamento de hardware para MongoDB com Graves


Sep 11, 2024 | 26 min
exemplo de código

Filme: exemplo de aplicativo de microsserviços Go


Sep 11, 2024 | 0 min read
Sumário