You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB单Upsert查询中实现仅更新生效字段(setOnInsert反向)

单查询实现Upsert时仅更新场景设置字段

核心思路

MongoDB确实没有直接对应$setOnInsert的反向操作符,但可以通过聚合管道式更新(MongoDB 4.2+支持)结合条件判断实现需求:

  • createdDate 依然用$setOnInsert在插入时设置
  • updatedDate 通过$cond判断:仅当文档已存在(更新场景)时才设置,插入时忽略该字段

Mongo Shell 实现方案

db.productModels.updateOne(
  { product_id: ObjectId("65b87bbc571dd2a8d301c9f2") },
  [
    {
      $set: {
        modelName: "orange 11",
        updatedDate: {
          $cond: {
            if: { $exists: ["$_id", true] }, // 文档存在则为更新场景
            then: new Date(),
            else: "$$REMOVE" // 插入场景下移除该字段,即不设置
          }
        }
      }
    },
    {
      $setOnInsert: {
        createdDate: new Date()
      }
    }
  ],
  { upsert: true }
)

Go 驱动实现方案

coll := mongoCon.Mongo.Collection("productModels")
productId, _ := primitive.ObjectIDFromHex("65b87bbc571dd2a8d301c9f2")

// 使用聚合管道作为更新文档
updatePipeline := bson.A{
    bson.D{
        {Key: "$set", Value: bson.D{
            {Key: "modelName", Value: "orange 11"},
            {Key: "updatedDate", Value: bson.M{
                "$cond": bson.M{
                    "if":   bson.M{"$exists": []interface{}{"$_id", true}},
                    "then": time.Now(),
                    "else": "$$REMOVE", // 插入时移除该字段,不设置
                },
            }},
        }},
    },
    bson.D{
        {Key: "$setOnInsert", Value: bson.D{
            {Key: "createdDate", Value: time.Now()},
        }},
    },
}

res, err := coll.UpdateOne(
    context.Background(),
    bson.M{"product_id": productId},
    updatePipeline,
    options.Update().SetUpsert(true),
)

if err != nil {
    log.Fatal(err)
}

关键说明

  • 使用聚合管道形式的更新,才能在更新逻辑中访问当前文档的字段状态($_id是否存在)
  • $$REMOVE是MongoDB的特殊变量,用于在聚合操作中移除指定字段,插入场景下使用它就能让updatedDate不被写入新文档
  • 该方案仅支持MongoDB 4.2及以上版本,这是聚合管道式更新的最低要求

内容的提问来源于stack exchange,提问作者Fath-Likki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 09:32:55