我有一份格式如下的文件:

{
  "f1": "v1",
  "f2": {
     "id": 1,
     "sub": "subv",
     "updatedAt": 123
   }
}

我有另一个来源,给我一个inputf2个物体.

Input:

{"id": 1,"sub": "newsubv","updatedAt": 100}

因为Output<123.id=1将不会被更新.Output:

{
  "f1": "v1",
  "f2": {"id": 1,"sub": "subv","updatedAt": 123}
}

Input:

{"id": 1,"sub": "newsubv","updatedAt": 150}

因为150>123.id=1将被更新.Output:

{
  "f1": "v1",
  "f2": {"id": 1,"sub": "newsubv","updatedAt": 150}
}

Input:

{"id": 2,"sub": "newsubv","updatedAt": 100}

因为在db中找不到输入id=2.不管updatedAt是多少,它都会被插入.Output:

{
  "f1": "v1",
  "f2": {"id": 1,"sub": "subv","updatedAt": 123}
},
{
  "f1": "v1",
  "f2": {"id": 2,"sub": "newsubv","updatedAt": 100}
}

我try 了两种类型的更新,更新文档或更新聚合管道,但似乎其中任何一种都符合我的要求.

With update document

我可以使用$setOnInsert,但不能将f2设置为f2.updatedAt < inputf2.updatedAt条件:

db.collection.update({
  "f2.id": "1"
},
{
  "$set": {
    // Can not check updatedAt = 100 < 123 and then do nothing
    "f2": {
      "id": 1
      "sub": "newsubv",
      "updatedAt": 100
    }
  },
  "$setOnInsert": {
    "f1": "v1"
  }
},
{"upsert": true});

With update aggregation pipeline

通过将f2克隆到新字段oldf2,然后应用条件并删除oldf2,我可以用f2.updatedAt < inputf2.updatedAt条件更新f2,但有点棘手.但在聚合中,没有$setOnItem函数:

db.test.updateOne(
{"f2.id": 1},
[
    {$set: {"oldf2": "$f2"}},
    {
        $set: {
            "f2": {
                $cond: [{$lt: ["$f2.updatedAt", 100]}, {
                    "id": 1,
                    "sub": "newsubv",
                    "updatedAt": 100
                }, "$oldf2"]
            }
        }
    },
    {$set: {"oldf2": "$$REMOVE"}},
    // How to apply something like $setOnInsert function?
],
{"upsert":true})

我必须使用updateOne,因为有一个f2项的列表,我想在bulkWrite中批量更新这些项.

Noted:f2.id是一个独特的Collection 领域

有人能帮我写下这个逻辑的查询吗?非常感谢你们.

推荐答案

最后,我可以编写查询.以下是我的解决方案:

db.test.updateOne(
{"f2.id": 1},
[{
  $set: {
    "f2": { $cond: [
        {$lt: ["$f2.updatedAt", 100]}, // time check condition
        {"id": 1,"sub": "newsubv","updatedAt": 100}, // overwrite value
        "$f2" // no change, return origin value
    ]},
    "f1": {$ifNull: ["$f1", "v1"]}, // this can do the same as $setOnInsert
  }
}],
{"upsert":true}
)

测试用例:

输入1:Mongo Playground

{"id": 1,"sub": "newsubv","updatedAt": 100}

输入2:Mongo Playground

{"id": 1,"sub": "newsubv","updatedAt": 200}

输入3:Mongo Playground

{"id": 2,"sub": "newsubv","updatedAt": 100}

Mongodb相关问答推荐

从MongoDB迁移到PostgreSQL:为PostgreSQL编写聚合管道查询

如何在查找 foreignField 中使用通配符?

MongoDB:从开始日期和结束日期数组中匹配特定日期的聚合查询

MongoDB 使用 pymongo 收集 500K 文档的写入速度很差

在 MongoDB 中加入多个集合

查询有关 Go 项目中对象数组的 MongoDb 集合

MongoDB - 在 $lookup 管道中匹配键匹配不起作用

如何使用 Golang 库获取 MongoDB 版本?

MongoDB 到 Snowflake 连续加载

当属性确实存在时,为什么mongoose模型的 hasOwnProperty 返回 false?

如何在 MongoDb 中进行类似于嵌套 Sql Select 查询的嵌套查询

Select 匹配mongodb中两个字段的concat值的记录

如何在 $lookup Mongodb 的 LocalField 中将字符串转换为 objectId

如何知道 MongoDB 集合大小?

使用管道聚合的 Spring Data MongoDB 查找

使用 Mongoid 和 Ruby 查询最近 30 天的日期范围?

MongoDB Compass 过滤器(查询)

如何向 mongodb 2.6 添加身份验证?

我在更新中对 $set 和 $inc 做错了什么

MongoDB:聚合框架: $match between fields