我一直在谷歌上搜索并阅读mongo文档,但觉得很奇怪没有人问这个,所以我以为我以错误的方式面对问题,但我坚持不懈,所以我要在这里问,我知道有一个
setOnInsert
mongo 中的
运算符在使用 upsert:true
时,setOnInsert
上的字段将在插入时插入,但在更新时忽略,但我想要的是,我希望某些字段仅在更新时保存,并在插入(更新插入)时忽略,与在单个查询中setOnInsert
。
所以这里是我有字段“createdDate”和“updatedDate”与
upsert:true
并使用setOnInsert
我可以在setOnInsert
上创建字段createdDate,但对于“updatedDate”如果我把它放在$set
它将在插入(upsert)时保存我希望“updatedDate”仅在更新时保存,但在一个查询中的插入(upsert)时被忽略。我可以用 2 个查询和更简单的查询来完成此操作,但寻找单个查询解决方案,还发现奇怪的 mongo 还没有 setOnInsert
的相反内容,也许这种情况很不寻常?
我尝试使用
$switch
和 $cond
但它被插入,因为文档不起作用,我尝试使用 mongo 的 go 驱动程序,但也接受作为 mongo 查询/shell 的答案(然后我自己转换它们)
coll := mongoCon.Mongo.Collection("productModels")
productId, _ := primitive.ObjectIDFromHex("65b87bbc571dd2a8d301c9f2")
doc := bson.D{
{Key: "$set", Value: bson.D{
{Key: "modelName", Value: "orange 11"},
{Key: "updatedDate", Value: bson.M{
"$switch": bson.M{
"branches": bson.A{
bson.M{
"case": bson.M{
"$eq": bson.A{
bson.M{"_id": bson.M{"$exists": false}}, false,
}},
"then": nil,
},
},
},
},
},
}},
{Key: "$setOnInsert", Value: bson.D{{Key: "createdDate", Value: time.Now()}}},
}
res, err := coll.UpdateOne(context.Background(), bson.M{"product_id": productId}, doc, options.Update().SetUpsert(true))
// throw res here now, might use it later for 2 query solution
_ = res
if err != nil {
log.Fatal(err)
}
在我看来,最简单的解决方案是即使对于新文档也可以插入
updatedDate
。如果您必须判断文档是否已更新,您可以比较 updatedDate
和 createdDate
,或者维护单独的 modifiedCount
字段。
现在来解决您的需求。您第二次尝试使用
$switch
不起作用,因为这是一个聚合运算符,并且要将聚合管道与更新操作一起使用,您必须使用数组(或切片)文档作为更新文档,这就是触发的原因将其解释为聚合管道。有关详细信息,请参阅 Golang 和 MongoDB - 我尝试使用 golang 将切换布尔值更新为 mongodb,但得到了对象。
这样做会引入一个新问题:你不能再使用
$setOnInsert
。并且您不能在聚合管道中使用 $exists
运算符:(
但是您想要的可以使用单个
$set
来实现:您可以使用 $ifNull
来检索字段的值(如果存在),或者提供后备值(如果不存在)。
因此,我们的想法是使用
createdDate
的当前值(如果存在),否则传递并设置当前时间。
类似地,如果
updatedDate
已经存在,我们只能更新 createdDate
,我们可以使用上面提到的 $ifNull
运算符进行检查(并使用 $cond
来判断结果是否为 null
)。
所以你可以这样做:
res, err := coll.UpdateOne(ctx,
bson.M{"product_id": productId},
[]any{
bson.M{
"$set": bson.M{
"modelName": "orange 11",
"updatedDate": bson.M{"$cond": []any{
bson.M{"$eq": []any{bson.M{"$ifNull": []any{"$createdDate", nil}}, nil}},
nil, time.Now(),
}},
"createdDate": bson.M{"$ifNull": []any{"$createdDate", time.Now()}},
},
},
},
options.Update().SetUpsert(true),
)
但是,我随时都更喜欢下面的解决方案,而不是上面的“丑陋”:
res, err = c.UpdateOne(ctx,
bson.M{"product_id": productId},
bson.M{
"$set": bson.M{
"modelName": "orange 11",
"updatedDate": time.Now(),
},
"$setOnInsert": bson.M{"createdDate": time.Now()},
},
options.Update().SetUpsert(true),
)