考虑以下 2 个结构:
type Struct1 struct {
foo string `bson:"foo,omitempty"`
bar string `bson:"bar,omitempty"`
Struct2 *struct2 `bson:"struct2,omitempty"`
}
type Struct2 struct {
foo string `bson:"foo,omitempty"`
bar string `bson:"bar,omitempty"`
}
使用 FindOneAndUpdate 并仅设置父级中的 foo 和嵌套结构中的 foo 的值具有以下行为。它保留了 db 文档中 struct1 bar 的现有值,这很好,但删除了嵌套在 struct2 对象中的 bar 值,这不太好。这是故意设计的吗?
如果我添加:
Struct2 *struct2 `bson:"struct2,omitempty,inline"`
它工作正常,但我丢失了 Mongo 中文档的结构,这并不理想。
编辑——添加最小可重现示例:
package main
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
// Connect to mongo
mongoClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI("mongodb://***:***@localhost:27017/test?connect=direct"))
if err != nil {
return
}
db := mongoClient.Database("test")
coll := db.Collection("test")
// Insert example record
id, err := coll.InsertOne(context.TODO(), bson.D{
{Key: "foo", Value: "foo_value"},
{Key: "bar", Value: "bar_value"},
{Key: "nestedObject", Value: bson.D{
{Key: "foo", Value: "foo_value"},
{Key: "bar", Value: "bar_value"},
},
}})
if err != nil {
fmt.Printf("Error: %v", err)
}
// Grab example record and print
result := &bson.D{}
coll.FindOne(context.TODO(), bson.M{"_id": id.InsertedID}).Decode(result)
fmt.Printf("Initial DB record -> %v\n", result)
// Update record, return SingleResult after and print
aft := options.After
opt := options.FindOneAndUpdateOptions{
ReturnDocument: &aft,
}
// Just changing foo, not bar
newResult := &bson.D{}
if err := coll.FindOneAndUpdate(context.TODO(), bson.M{"_id": id.InsertedID}, bson.D{{Key: "$set", Value: bson.D{
{Key: "foo", Value: "foo_changed"},
{Key: "nestedObject", Value: bson.D{
{Key: "foo", Value: "foo_changed"},
},
}}}}, &opt).Decode(newResult); err != nil {
fmt.Printf("Error: %v", err)
}
fmt.Printf("Updated DB record -> %v\n", newResult)
}
输出以下内容,我的nestedObject.bar去哪里了??? (注意非嵌套的仍然存在):
Initial DB record -> &[{_id ObjectID("65d8f675a5418eef83425156")} {foo foo_value} {bar bar_value} {nestedObject [{foo foo_value} {bar bar_value}]}]
Updated DB record -> &[{_id ObjectID("65d8f675a5418eef83425156")} {foo foo_changed} {bar bar_value} {nestedObject [{foo foo_changed}]}]
这解释了为什么在 bson 上使用“,inline”效果很好,因为 bson.D 在更新之前已被展平。
问题是,是否可以保留嵌套结构并让 mongo 只更新提供的值?
您的更新操作将
nestedObject
字段设置为具有单个 foo
属性的对象。这就是为什么它的 bar
字段消失了。
如果您只想更改嵌套对象
foo
内的 nestedObject
,请使用“点”表示法:
// Just changing foo, not bar
newResult := &bson.D{}
if err := coll.FindOneAndUpdate(context.TODO(),
bson.M{"_id": id.InsertedID},
bson.D{{Key: "$set", Value: bson.D{
{Key: "foo", Value: "foo_changed"},
{Key: "nestedObject.foo", Value: "foo_changed"},
}}}, &opt).Decode(newResult); err != nil {
fmt.Printf("Error: %v", err)
}