15

我正在尝试在 MongoDB 中使用 upsert 来更新文档中的单个字段(如果找到)或插入一个包含大量字段的全新文档。问题是在我看来,MongoDB 要么替换每个字段,要么在其 upsert 操作中插入字段的子集,即它不能插入比它实际想要更新的更多的字段。

我想要做的是以下内容:

  • 我查询单个唯一值
  • 如果文档已经存在,则仅将时间戳值(我们称之为“lastseen”)更新为新值
  • 如果文档不存在,我将添加一长串不同的键/值对,这些键/值对在其剩余生命周期内应保持静态。

让我们来说明:

根据我的理解,如果找到“name”,则此示例将更新“lastseen”日期,但如果未找到“name”,则只会插入“name”+“lastseen”。

db.somecollection.update({name: "some name"},{ $set: {"lastseen": "2012-12-28"}}, {upsert:true})

如果我向第二个参数添加更多字段(键/值对)并删除 $set,则每个字段都会在更新时被替换,但会对插入产生预期效果。是否有类似 $insert 或类似的东西仅在插入时执行操作?

所以在我看来,我只能得到以下之一:

  • 正确的更新行为,但如果文档不存在,将插入仅包含所需字段子集的文档
  • 正确的插入行为,但如果文档已经存在,则会覆盖所有现有字段

我的理解正确吗?如果是这样,是否可以通过一次操作来解决?

4

2 回答 2

38

MongoDB 2.4 有$setOnInsert

db.somecollection.update(
    {name: "some name"},
    {
        $set: {
            "lastseen": "2012-12-28"
        },
        $setOnInsert: {
            "firstseen": <TIMESTAMP>  # set on insert, not on update
        }
    },
    {upsert:true}
)
于 2013-04-11T16:01:18.773 回答
8

对此有一个功能请求(https://jira.mongodb.org/browse/SERVER-340),已在 2.3 中解决。奇数版本实际上是开发版本,所以这将在 2.4 稳定版中。

所以目前的稳定版本还没有真正的方法来做到这一点。恐怕唯一的方法是实际执行 3 个条件查询 atm:1 检查行,然后if进行插入或更新。

我想如果您在这里遇到真正的锁定问题,您可以使用唯一的 JS 来执行此功能,但这很邪恶,但它会将这个更新锁定到单个线程。

于 2012-12-31T09:02:44.517 回答