带有 omitempty 的 Mongo 嵌套结构

问题描述 投票:0回答:1

考虑以下 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 只更新提供的值?

mongodb go bson mongo-go go-structtag
1个回答
0
投票

您的更新操作将

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)
}
© www.soinside.com 2019 - 2024. All rights reserved.