MongoDB $push vs $addToSet:有什么区别?

发布于

MongoDB有一个运算符和一个运算符,它们都做非常相似的事情。[$push](https://database.guide/mongodb-push/ "MongoDB $push")``[$addToSet](https://database.guide/mongodb-addtoset/ "MongoDB $addToSet")

这两个运算符都将值追加到现有数组。主要区别在于它们如何处理已经包含您尝试追加的值的数组,以及可以使用的修饰符。

差异

| 现有值 | 如果数组中已存在该值,则仍将附加该值(导致重复值)。 但是,仅当数组中尚不存在该值时,才会追加该值。因此,如果该值已存在,则不会追加它(它不会执行任何操作)。$push``$addToSet``$addToSet | | 修饰 符 | 运算符可以与其他修饰符一起使用,例如、和 ,而不能(至少在MongoDB 4.4 中不是)。$push``$sort``$slice``$position``$addToSet |

现有值

假设我们有一个包含以下文档的集合:

db.players.find()

输出:

{ "_id" : 1, "scores" : [ 1, 5, 3 ] }
{ "_id" : 2, "scores" : [ 8, 17, 18 ] }
{ "_id" : 3, "scores" : [ 3, 5, 5 ] }

让我们尝试将一个值附加到其中一个数组。$addToSet

db.players.update(
   { _id: 3 },
   { $addToSet: { scores: 5 } }
)

输出:

WriteResult({ “nMatched” : 1, “nUpserted” : 0, “nModified” : 0 })

这告诉我们有一个匹配的文档(文档 3),但它没有被修改。它没有被修改,$1()已经存在于数组中。5

让我们看看集合:

db.players.find()

输出:

{ "_id" : 1, "scores" : [ 1, 5, 3 ] }
{ "_id" : 2, "scores" : [ 8, 17, 18 ] }
{ "_id" : 3, "scores" : [ 3, 5, 5 ] }

正如预期的那样,文档 3 尚未更改。

让我们试试:$push

db.players.update(
   { _id: 3 },
   { $push: { scores: 5 } }
)

输出:

WriteResult({ “nMatched” : 1, “nUpserted” : 0, “nModified” : 1 })

这次我们看到文档已被修改。

我们可以通过再次检查集合来验证这一点:

db.products.find()

输出:

{ "_id" : 1, "scores" : [ 1, 5, 3 ] }
{ "_id" : 2, "scores" : [ 8, 17, 18 ] }
{ "_id" : 3, "scores" : [ 3, 5, 5, 5 ] }

修饰 符

运算符可以与修饰符一起使用,例如 、 和 。$push``$position``$sort``$slice

运算符不能与这些修饰符一起使用。$addToSet

如果我尝试将这些修饰符与以下方面一起使用,会发生什么:$addToSet

db.players.update(
   { _id: 3 },
   { 
     $addToSet: { 
        scores: {
           $each: [ 12 ],
           $position: 0,
           $sort: 1,
           $slice: 5
        }
      } 
    }
)

输出:

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 }” } })

错误消息告诉我们,、 和 是意外字段(即它们不应该在那里)。$position``$sort``$slice

让我们尝试使用:$push

db.players.update(
   { _id: 3 },
   { 
     $push: { 
        scores: {
           $each: [ 12 ],
           $position: 0,
           $sort: 1,
           $slice: 5
        }
      } 
    }
)

输出:

WriteResult({ “nMatched” : 1, “nUpserted” : 0, “nModified” : 1 })

这次它没有出错。

验证结果:

db.players.find()

输出:

{ "_id" : 1, "scores" : [ 1, 5, 3 ] }
{ "_id" : 2, "scores" : [ 8, 17, 18 ] }
{ "_id" : 3, "scores" : [ 3, 5, 5, 5, 12 ] }

我们可以看到该值已被附加。即使我们指定了,我们也指定了,这意味着数组在我们定位后被排序。$position: 0``$sort: 1

我们还指定了 ,它将数组限制为只有 5 个元素(事实证明,这正是数组中有多少个元素)。$slice: 5