MongoDB - 更新记录






4.36/5 (5投票s)
用于解释 MongoDB 中更新项目的查询
引言
我在上一篇文章中介绍了 MongoDB 的基本查询(select
、insert
和 delete
),现在将在此描述如何在 MongoDB 中更新记录。Update
记录是任何数据库所需的四种基本 CRUD 操作(create
、read
、update
和 delete
)之一。MondoDB 也提供了其更新查询,功能更加强大。
MongoDB 中的 Update
查询功能不像 SQL 数据库那样直接。它是一个比简单 update
更强大的功能组件。您会发现它有助于完成日常开发任务的通用操作,并且我们可以使数据库操作更加简单,减少数据层的复杂性。
背景
Update
查询能够执行以下操作:
- 它可以替换整个文档(请记住,您可以将其视为 .NET 环境中的
DataRow
)。 - 像简单的 SQL 数据库一样更新记录,您指定的字段数量将根据提供的条件进行更新。
- 提供特殊的
$inc
修饰符,如果您需要增加或减少字段的值。 $push
修饰符将一个值添加到数组中(请记住,您可以在文档的字段中放置整个数组)。- upsert 会在找到文档时更新它,如果找不到则插入它。
描述
最简单的形式下,update
接受 2 个参数:用于选择(where)的条件和要更新的字段。如果 Imran 需要更改他扮演的类别,我们可以执行
db.KarachiTigers.update({name: 'Imran'}, {category: 'Bowler'})
如果这是真实的代码,您可能需要通过 _id
来更新记录,但由于我不知道 MongoDB 为您生成的 _id
是什么,我们将继续使用姓名。现在,如果我们查看更新后的记录
db.KarachiTigers.find({name: 'Imran'})
您应该会发现更新的第一个惊喜。找不到任何文档,因为我们提供的第二个参数用于替换原始文档。换句话说,更新根据名称找到了一个文档,并用新文档(第二个参数)替换了整个文档。这与 SQL 的 update
命令的工作方式不同。在某些情况下,这是理想的,并且可以利用它来进行一些真正的动态更新。然而,当您只想更改一个或几个字段的值时,最好使用 MongoDB 的 $set
修饰符。
db.KarachiTigers.update({name: 'Imran'}, {$set: {category: 'Bowler', dob: new Date
(1979, 7, 18, 18, 44), hobbies: ['cricket'], gender: 'm'}})
这将重置丢失的字段。它不会覆盖新的 category,因为我们没有指定它。现在如果我们执行
db.KarachiTigers.find({name: 'Imran'})
我们得到了预期的结果。因此,最初正确更新 category 的方法是
db.KarachiTigers.update({name: 'Imran'}, {$set: {category: 'Bowler'}})
除了 $set
,我们还可以利用其他修饰符来做一些有趣的事情。所有这些更新修饰符都作用于字段,因此您的整个文档不会被清除。例如,$inc
修饰符用于按一定的正数或负数金额增加字段的值。例如,如果 Amir 被错误地判了一个三柱门,我们可以通过执行以下命令来纠正错误
db.KarachiTigers.update({name: 'Amir'}, {$inc: {wickets: -1}})
如果 Saeed Ajmal 需要更新他的投球动作,例如,他可以投出 off-spin 和 doosra,我们可以设置文档中 actions 字段定义的数组项
db.KarachiTigers.update({name: 'Saeed Ajmal'}, {$set: {actions: ['off-spin', 'doosra']}})
假设 Saeed Ajmal 突然开发了一种 teesra 投球动作,我们可以通过 $push
修饰符向他的 actions 字段添加一个值
db.KarachiTigers.update({name: 'Saeed Ajmal'}, {$push: {actions: 'teesra'}})
MongoDB 网站的更新部分提供了有关其他可用 update
修饰符的更多信息。
Update 的一个令人愉快的惊喜是它完全支持 upserts
。upsert
会在找到文档时更新它,如果找不到则插入它。Upserts
在某些情况下非常方便,当您遇到这种情况时,您就会知道。要启用 upsert,我们将第三个参数设置为 true
。一个日常的例子是网站的点击计数器。如果我们想实时维护一个聚合计数,我们就必须查看该页面是否已有记录,并根据此决定是运行 update
还是 insert
。如果省略第三个参数(或设置为 false
),执行以下操作将不会产生任何结果
db.hits.update({page: 'cricket updates'}, {$inc: {hits: 1}});
db.hits.find();
然而,如果我们启用 upserts
,结果将截然不同
db.hits.update({page: 'cricket updates'}, {$inc: {hits: 1}}, true);
db.hits.find();
由于不存在字段 page 等于 cricket updates 的文档,因此会插入一个新文档。如果我们第二次执行它,现有文档将被更新,点击次数将增加到 2。
db.hits.update({page: 'cricket updates'}, {$inc: {hits: 1}}, true);
db.hits.find();
非 upsert
的更新可能会也可能不会修改现有对象。upsert
将会修改现有对象或插入新对象。客户端可以通过随后发出 getlasterror
命令(db.runCommand( "getlasterror" )
)来确定连接上的最新消息是否更新了现有对象。
- 如果
getlasterror
命令的结果包含一个updatedExisting
字段,则连接上的最后一条消息是一个update
请求。 - 如果
updatedExisting
字段的值为true
,则该update
请求导致现有对象被更新 - 如果
updatedExisting
为false
,则没有现有对象被更新。 - 如果执行了
insert
,则“upserted
”字段将包含新的_id
值。
Update 提供的最后一个惊喜是,默认情况下,它将 update
单个文档。到目前为止,对于我们看过的示例,这似乎是合乎逻辑的。但是,如果您执行类似以下操作
db.KarachiTigers.update({}, {$set: {qualified: true }});
db.KarachiTigers.find({qualified: true});
您可能会期望找到所有团队成员都合格。要获得您想要的行为,必须将第四个参数设置为 true
db.KarachiTigers.update({}, {$set: {qualified: true }}, false, true);
db.KarachiTigers.find({qualified: true});
关注点
我们完成了对集合可用的基本 CRUD 操作的介绍。我们详细研究了 update
,并观察了三个有趣的现象。首先,与 SQL 的 update
不同,MongoDB 的 update
会替换实际文档。因此,$set
修饰符非常有用。其次,update
支持直观的 upsert
,当与 $inc
修饰符结合使用时尤其有用。最后,默认情况下,update
只更新找到的第一个文档。请记住,我们是从 shell 的角度来看待 MongoDB 的。您使用的驱动程序和库可能会改变这些默认行为或公开不同的 API。
历史
- 2012 年 2 月 27 日:初始版本