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).