MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

MongoDB $ push vs $ addToSet:Qual é a diferença?


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