为了账号安全,请及时绑定邮箱和手机立即绑定

编组结构时用嵌入的 json 替换 ObjectId

编组结构时用嵌入的 json 替换 ObjectId

Go
回首忆惘然 2021-10-11 10:54:26
我正在使用 Go 和 MongoDB 构建一个 RESTful API,并且在将一个文档的 JSON 嵌入另一个文档的 JSON 中遇到了一些困难。这是我正在尝试完成的一个玩具示例。我有以下模式:type Post struct {    ID    bson.ObjectId `json:"id,omitempty"`    Title string        `json:"title,omitempty"`    Owner bson.ObjectId `json:"owner,omitempty"` // references a User}type User struct {    ID   bson.ObjectId `json:"id,omitempty"`    Name string        `json:"name,omitempty"`}在为帖子创建 JSON 时,我想首先在 MongoDB 中查找帖子的所有者,并将生成的用户嵌入到所述帖子的 JSON(代替原始 JSON ObjectId)中,如下所示:{    "id": "...",    "title": "My awesome post",    "owner": {        "id": "...",        "name": "Cody"    }}除了使用 手动构建 JSON 之外,我不太确定如何完成此操作map[string]interface{},如下所示:post := LookupPost(...)user := LookupUser(post.Owner)m := map[string]interface{}{    "id": post.ID,    "title": post.Title,    "owner": map[string]interface{}{        "id": user.ID,        "name": user.Name,    },}b, _ := json.Marshal(m)理想情况下,我能够利用json每个结构定义中的标签并自动插入字段。我是否遗漏了什么,或者我试图做的事情是不可能的?或者我只是没有正确地在 Go 中接近 MongoDB/JSON?从正确的角度来看,我来自 Node.js 背景,在那里这种功能是微不足道的。
查看完整描述

2 回答

?
Helenr

TA贡献1780条经验 获得超4个赞

我不熟悉 MongoDB 或bson.ObjectId,但是您能否将您自己的类型替换为您的User字段,并让 MongoDB 轻松地从用户的bson.ObjectId.


如果是这样,您可以将用户对象 id 包装到他们自己的实现json.Marshaler接口的类型中。例如:


// Embedded (instead of `type x bson.ObjectId`) so that we

// get all the methods and satisfy all the interfaces that

// bson.ObjectId does. Hopefully that's engough to allow MongoDB

// to fill in fields of this type from a database??

type ownerObjID struct{ bson.ObjectId }


// Here we marshal the results of looking up the user from the id

// rather than just the ID itself.

func (oid ownerObjID) MarshalJSON() ([]byte, error) {

    user, err := LookupUser(oid.ObjectId)

    if err != nil {

        return nil, err

    }

    return json.Marshal(user)

}


type Post struct {

    ID    bson.ObjectId `json:"id,omitempty"`

    Title string        `json:"title,omitempty"`

    Owner ownerObjID    `json:"owner,omitempty"` // <-- is this type wrapping doable/easy with MongoDB?

}


type User struct {

    ID   bson.ObjectId `json:"id,omitempty"`

    Name string        `json:"name,omitempty"`

}


func main() {

    post := LookupPost()

    b, err := json.MarshalIndent(post, "", "  ")

    if err != nil {

        log.Fatal(err)

    }

    fmt.Printf("JSON:\n%s\n", b)

}


// Some stubs for demo:

func LookupPost() Post {

    return Post{

        ID:    "postID001",

        Title: "Ima Test",

        Owner: ownerObjID{"ownerID002"},

    }

}


func LookupUser(id bson.ObjectId) (User, error) {

    return User{

        ID:   id,

        Name: "name for " + string(id),

    }, nil

}

Playground


给我:


JSON:

{

  "id": "postID001",

  "title": "Ima Test",

  "owner": {

    "id": "ownerID002",

    "name": "name for ownerID002"

  }

}


查看完整回答
反对 回复 2021-10-11
?
慕少森

TA贡献2019条经验 获得超9个赞

所以我实际上发现了一个更清晰的解决这个问题的方法:


type Post struct {

    ID bson.ObjectId `bson:"_id,omitempty" json:"id,omitempty"`

    Title string `bson:"title,omitempty" json:"title,omitempty"`

    Owner UserRef `bson:"owner,omitempty" json:"owner,omitempty"`

}


type User struct {

    ID   bson.ObjectId `json:"id,omitempty"`

    Name string        `json:"name,omitempty"`

}


type UserRef bson.ObjectId


func (ref UserRef) GetBSON() (interface{}, error) {

    return bson.ObjectId(ref), nil

}


func (ref UserRef) MarshalJSON() ([]byte, error) {

    u := LookupUserInMongoDB(ref)


    return json.Marshal(u)

}

这是它的工作原理——在将 Post 转换为 bson 时,mgo 无法将 UserRef 存储为 ObjectId,因此我们可以实现GetBSONUserRef的方法以返回底层 ObjectId。这允许我们将 Owner 作为 ObjectId 存储在数据库中。而且,就像在@DaveC 的回答中一样,我们实现了MarshalJSONUserRef的方法,以便在将 Post 转换为 json 时,我们可以用实际嵌入的用户替换 ObjectId。


查看完整回答
反对 回复 2021-10-11
  • 2 回答
  • 0 关注
  • 185 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信