匿名结构体返回空字段值

huangapple go评论96阅读模式
英文:

Anonymous structs return empty field value

问题

类型(

Id 结构体 {
    // 我之前忘记在我的问题中添加 `ID` 字段,它在我的代码中存在,但在这个问题中没有,正如 @icza 指出的那样
    ID bson.ObjectId `json:"id" bson:"_id"`
}

User 结构体 {
    // 使用匿名结构体时,在返回集合时,每个文档的 `id` 字段都将是空字符串 `""`
    Id
    Email string `json:"email" bson:"email"`
    ...
}

// 这个是可以工作的
User2 结构体 {
    ID bson.ObjectId `json:"id" bson:"_id"`
    Email string `json:"email" bson:"email"`
}

)

我可能还没有完全理解匿名结构体的概念。在上面的示例中,当从集合中查询所有用户时,id 字段将是一个空字符串 ""。然而,如果我直接在 User 结构体中定义 ID 字段,id 就会正常显示。这不是匿名结构体的用途吗?基本上是扩展结构体,这样你就不必一遍又一遍地输入它们了。

更多示例:

类型 SoftDelete 结构体 {
CreatedAt time.Time json:"created_at" bson:"created_at"
UpdatedAt time.Time json:"updated_at" bson:"updated_at"
DeletedAt time.Time json:"deleted_at" bson:"deleted_at"
}

类型 UserModel 结构体 {
SoftDelete
}

类型 BlogPost 结构体 {
SoftDelete
}

英文:
type (

    Id struct {
        // I previously forgot to add the `ID` field in my question, it is present in my code but not on this question as @icza pointed it out to me
        ID bson.ObjectId `json:"id" bson:"_id"`
    }

    User struct {
        // When using anonymous struct, upon returning the collection, each of the document will have an empty `id` field, `id: ""`
        Id
        Email string `json:"email" bson:"email"`
        ...
    }

    // This works
    User2 struct {
        ID bson.ObjectId `json:"id" bson:"_id"`
        Email string `json:"email" bson:"email"`
    }
)

I might not have fully understood the concept of anonymous structs yet. In the example above, when querying all users from a collection, the id field is going to be an empty string "". However, if I directly define the ID field in the User struct, the id shows up fine. Is this not what anonymous structs are for? Basically extending struct so you won't have to type them again and again?

More example:

type SoftDelete struct {
    CreatedAt time.Time `json:"created_at" bson:"created_at"`
    UpdatedAt time.Time `json:"updated_at" bson:"updated_at"`
    DeletedAt time.Time `json:"deleted_at" bson:"deleted_at"`
}

type UserModel struct {
    SoftDelete
}

type BlogPost struct {
    SoftDelete
}

答案1

得分: 5

这里的问题是,具有struct类型(包括嵌入的结构体)的字段在MongoDB中作为嵌入文档出现。如果你不想这样,你需要在嵌入结构体时指定"inline" bson标志:

User struct {
    Id           `bson:",inline"`
    Email string `json:"email" bson:"email"`
}

"inline"标签的作用是在MongoDB中将嵌入结构体的字段“展开”,就好像它们是嵌入结构体的一部分一样。

类似地:

type UserModel struct {
    SoftDelete `bson:",inline"`
}

type BlogPost struct {
    SoftDelete `bson:",inline"`
}

编辑:下面的部分适用于原始的Id类型,它嵌入了bson.ObjectId。提问者后来澄清这只是一个拼写错误(并且编辑了问题),它是一个命名的非匿名字段。但我仍然认为下面的信息是有用的。

关于你的Id类型,有一点需要注意:你的Id类型也嵌入了bson.ObjectId

Id struct {
    bson.ObjectId `json:"id" bson:"_id"`
}

Id不仅有一个bson.ObjectId类型的字段,而且它嵌入了它。这很重要,因为这样你的Id类型将从bson.ObjectId继承一个String()方法,而User也会继承这个方法,因为它嵌入了Id。话虽如此,尝试打印或调试User类型的值会很困难,因为你总是只会看到它作为一个单独的ObjectId打印出来。

相反,你可以将它作为Id的普通字段,嵌入User仍然会按预期工作:

Id struct {
    ID bson.ObjectId `json:"id" bson:"_id"`
}

参考相关问题+答案:https://stackoverflow.com/questions/41595577/enforce-a-type-mapping-with-mgo/41596169#41596169

英文:

The problem here is that fields having struct types (including embedded structs) appear as embedded documents in MongoDB. If you don't want this, you have to specify the "inline" bson flag when embedding a struct:

User struct {
    Id           `bson:",inline"`
    Email string `json:"email" bson:"email"`
}

What the "inline" tag does is in MongoDB it "flattens" the fields of the embedded struct as if they were part of the embedder struct.

Similarly:

type UserModel struct {
    SoftDelete `bson:",inline"`
}

type BlogPost struct {
    SoftDelete `bson:",inline"`
}

<sup>Edit: the following section applies to the original Id type which embedded bson.ObjectId. The asker later clarified that this was just a typo (and edited the question since), and it is a named, non-anonymous field. Still think the info below is useful.</sup>

One thing to note about your Id type: Your Id type also embeds bson.ObjectId:

Id struct {
    bson.ObjectId `json:&quot;id&quot; bson:&quot;_id&quot;`
}

Id not just has a field of bson.ObjectId, but it embeds it. This matters because this way you Id type will have a String() method promoted from bson.ObjectId, and so will User which embeds Id. Having said that, it will be hard trying to print or debug values of type User, because you will always see it printed just as a single ObjectId.

Instead you can make it a regular field in Id, embedding Id in User will still work as expected:

Id struct {
    ID bson.ObjectId `json:&quot;id&quot; bson:&quot;_id&quot;`
}

See related question+asnwer: https://stackoverflow.com/questions/41595577/enforce-a-type-mapping-with-mgo/41596169#41596169

huangapple
  • 本文由 发表于 2017年1月30日 23:04:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/41939080.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定