65.9K
CodeProject 正在变化。 阅读更多。
Home

MongoDB - 更新记录

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.36/5 (5投票s)

2012年2月28日

CPOL

5分钟阅读

viewsIcon

44401

用于解释 MongoDB 中更新项目的查询

引言

我在上一篇文章中介绍了 MongoDB 的基本查询(selectinsertdelete),现在将在此描述如何在 MongoDB 中更新记录。Update 记录是任何数据库所需的四种基本 CRUD 操作(createreadupdatedelete)之一。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 的一个令人愉快的惊喜是它完全支持 upsertsupsert 会在找到文档时更新它,如果找不到则插入它。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 请求导致现有对象被更新
  • 如果 updatedExistingfalse,则没有现有对象被更新。
  • 如果执行了 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 日:初始版本
© . All rights reserved.