MongoDB tem um
$push operador e um $addToSet operador, ambos os quais fazem uma coisa muito semelhante. Ambos os operadores acrescentam valores a uma matriz existente. A principal diferença está em como eles lidam com arrays que já contêm o valor que você está tentando anexar e também nos modificadores que podem ser usados.
As diferenças
| Valores existentes | Se o valor já existir no array, $push ainda anexará o valor (resultando em valores duplicados). No entanto, $addToSet só acrescenta o valor se ele ainda não existir na matriz. Portanto, se o valor já existir, $addToSet não irá anexá-lo (não fará nada). |
| Modificadores | O $push operador pode ser usado com modificadores adicionais, como $sort , $slice e $position , enquanto $addToSet não pode (pelo menos, não a partir do MongoDB 4.4). |
Valores existentes
Suponha que temos uma coleção com os seguintes documentos:
db.players.find() Resultado:
{ "_id" : 1, "scores" : [ 1, 5, 3 ] }
{ "_id" : 2, "scores" : [ 8, 17, 18 ] }
{ "_id" : 3, "scores" : [ 3, 5, 5 ] } Vamos usar
$addToSet para tentar anexar um valor a uma das matrizes. db.players.update(
{ _id: 3 },
{ $addToSet: { scores: 5 } }
) Saída:
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 }) Isso nos diz que havia um documento correspondente (documento 3), mas não foi modificado. Não foi modificado porque o valor que tentamos inserir (
5 ) já existe na matriz. Vejamos na coleção:
db.players.find() Resultado:
{ "_id" : 1, "scores" : [ 1, 5, 3 ] }
{ "_id" : 2, "scores" : [ 8, 17, 18 ] }
{ "_id" : 3, "scores" : [ 3, 5, 5 ] } Como esperado, o documento 3 não foi alterado.
Vamos tentar
$push em vez de:db.players.update(
{ _id: 3 },
{ $push: { scores: 5 } }
) Saída:
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) Desta vez vemos que o documento foi modificado.
Podemos verificar isso verificando a coleção novamente:
db.products.find() Resultado:
{ "_id" : 1, "scores" : [ 1, 5, 3 ] }
{ "_id" : 2, "scores" : [ 8, 17, 18 ] }
{ "_id" : 3, "scores" : [ 3, 5, 5, 5 ] } Modificadores
O
$push operador pode ser usado com modificadores como $position , $sort e $slice . O
$addToSet operador não pode ser usado com esses modificadores. Aqui está o que acontece se eu tentar usar esses modificadores com
$addToSet :db.players.update(
{ _id: 3 },
{
$addToSet: {
scores: {
$each: [ 12 ],
$position: 0,
$sort: 1,
$slice: 5
}
}
}
) Saída:
WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" : {
"code" : 2,
"errmsg" : "Found unexpected fields after $each in $addToSet: { $each: [ 12.0 ], $position: 0.0, $sort: 1.0, $slice: 5.0 }"
}
}) A mensagem de erro nos diz que o
$position , $sort e $slice são campos inesperados (ou seja, eles não deveriam estar lá). Vamos tentar os mesmos modificadores com
$push :db.players.update(
{ _id: 3 },
{
$push: {
scores: {
$each: [ 12 ],
$position: 0,
$sort: 1,
$slice: 5
}
}
}
) Saída:
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) Desta vez funcionou sem erro.
Verifique o resultado:
db.players.find() Resultado:
{ "_id" : 1, "scores" : [ 1, 5, 3 ] }
{ "_id" : 2, "scores" : [ 8, 17, 18 ] }
{ "_id" : 3, "scores" : [ 3, 5, 5, 5, 12 ] } Podemos ver que o valor foi anexado. Embora tenhamos especificado
$position: 0 , também especificamos $sort: 1 , o que significa que a matriz foi classificada depois que a posicionamos. Também especificamos
$slice: 5 , que limitava a matriz a apenas 5 elementos (que, como se viu, era exatamente quantos elementos estavam na matriz de qualquer maneira).