如何在mgo中使用单个集合处理多种类型的数据?

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

How to work with multiple types in single collection with mgo

问题

我非常新手golang,并尝试使用mongodb作为后端数据库编写一个简单的事件溯源用户管理webapi。现在我有一个名为User的结构体,大致如下:

type User struct {
    Id       bson.ObjectId `json:"id" bson:"_id"`
    UserName string        `json:"username" bson:"username"`
    Email    string        `json:"email" bson:"email"`
    PwdHash  string        `json:"pwd_hash" bson:"pwd_hash"`
    FullName string        `json:"fullname" bson:"fullname"`
}

还有三个事件,当有人使用api时会发生:

type UserCreatedEvent struct {
    UserId         bson.ObjectId `json:"id" bson:"_id"`
    CreatedEpoch   time.Time     `json:"created_epoch" bson:"created_epoch"`
    IssuedByUserId bson.ObjectId `json:"issuedby_userid" bson:"issuedby_userid"`
}

type UserDeletedEvent struct {
    UserId         bson.ObjectId `json:"id" bson:"_id"`
    CreatedEpoch   time.Time     `json:"created_epoch" bson:"created_epoch"`
    IssuedByUserId bson.ObjectId `json:"issuedby_userid" bson:"issuedby_userid"`
}

type UserUpdatedEvent struct {
    UserId               bson.ObjectId `json:"id" bson:"_id"`
    CreatedEpoch         time.Time     `json:"created_epoch" bson:"created_epoch"`
    IssuedByUserId       bson.ObjectId `json:"issuedby_userid" bson:"issuedby_userid"`
    ChangedFieldName     string        `json:"changed_field_name" bson:"changed_field_name"`
    NewChangedFieldValue string        `json:"new_changed_field_value" bson:"new_changed_field_value"`
}

现在我在保存和从数据库检索事件时遇到了困难。问题是我想将它们存储在一个单独的集合中,以便我拥有用户修改的完整历史记录。但我找不到如何正确存储事件类型名称作为mongo文档字段,然后在搜索中使用它。有什么惯用的go方式可以做到这一点吗?

非常感谢任何帮助。

英文:

I'm very new to golang and try to write a simple event-sourcing user-management webapi using mongodb as backing database. Now i have User, which looks something like this:

type User struct {
Id       bson.ObjectId `json:"id" bson:"_id"`
UserName string        `json:"username" bson:"username"`
Email    string        `json:"email" bson:"email"`
PwdHash  string        `json:"pwd_hash" bson:"pwd_hash"`
FullName string        `json:"fullname" bson:"fullname"`
}

and three events, happening to user, when somebody uses api:

type UserCreatedEvent struct {
	UserId         bson.ObjectId `json:"id" bson:"_id"`
	//time when event was issued
	CreatedEpoch   time.Time     `json:"created_epoch" bson:"created_epoch"`
	//id of user that made a change
	IssuedByUserId bson.ObjectId `json:"issuedby_userid" bson:"issuedby_userid"`
}

type UserDeletedEvent struct {
	UserId         bson.ObjectId `json:"id" bson:"_id"`
	CreatedEpoch   time.Time     `json:"created_epoch" bson:"created_epoch"`
	//id of user that made a change
	IssuedByUserId bson.ObjectId `json:"issuedby_userid" bson:"issuedby_userid"`
}

type UserUpdatedEvent struct {
	UserId         bson.ObjectId `json:"id" bson:"_id"`
	CreatedEpoch   time.Time     `json:"created_epoch" bson:"created_epoch"`
	//id of user that made a change
	IssuedByUserId bson.ObjectId `json:"issuedby_userid" bson:"issuedby_userid"`
	ChangedFieldName     string  `json:"changed_field_name" bson:"changed_field_name"`
	NewChangedFieldValue string  `json:"new_changed_field_value" bson:"new_changed_field_value"`
}

Now i'm stuck on saving and retrieving events from db. The problem is i want to store them in a single collection, so that i have a full plain history of user modifications. But i can't find how to correctly store event type name as a mongo document field and then use it in searches. What is the idiomatic go-way to do this?

I'll be gratefull for any help.

答案1

得分: 0

非关系型数据库的好处是可以容忍一些冗余,并且由于不需要进行连接操作,所以检索速度更快。你可以将你的底部三个对象作为User的属性以适合你和你的数据的方式添加进去。这样,你也不需要在这些对象上存储UserId

如果你需要快速搜索Events,你可以创建另一个集合来存储它们。你将会向两个集合插入数据,但检索时间和逻辑应该相当不错/易于编写。

你的新Event可能是这样的:

type UserEventType int

const (
    Created UserEventType = iota
    Deleted
    Updated
)

type UserEvent struct {
    UserId               bson.ObjectId `json:"id" bson:"_id"`
    CreatedEpoch         time.Time     `json:"created_epoch" bson:"created_epoch"`
    //id of user that made a change
    IssuedByUserId       bson.ObjectId `json:"issuedby_userid" bson:"issuedby_userid"`
    ChangedFieldName     string        `json:"changed_field_name,omitempty" bson:"changed_field_name,omitempty"`
    NewChangedFieldValue string        `json:"new_changed_field_value,omitempty" bson:"new_changed_field_value,omitempty"`
    EventType            UserEventType `json:"user_event_type" bson:"user_event_type"`
}

请注意,字段上的omitempty表示根据事件类型是否可选。

实际上,你不应该将不同的对象存储在同一个集合中。以下是Mongo文档中的一句话:

> MongoDB将文档存储在集合中。集合类似于关系数据库中的表。

如果你对关系数据库不熟悉,表实质上代表一种类型的对象。

英文:

What's nice about a non-relational database is that a little redundancy is OK and is faster for retrieval since you're not joining things together. You could just add your bottom three objects as properties on your User in whatever fashion makes sense for you and your data. Then you wouldn't need to store the UserId on those objects either.

If you need to search over the Events quickly, you could create another collection to hold them. You'd be inserting to two collections, but retrieval times/logic should be pretty good/easy to write.

Your new Event would be something like:

type UserEventType int

const (
    Created UserEventType = iota
    Deleted
    Updated
)

type UserEvent struct {
    UserId               bson.ObjectId `json:"id" bson:"_id"`
    CreatedEpoch         time.Time     `json:"created_epoch" bson:"created_epoch"`
    //id of user that made a change
    IssuedByUserId       bson.ObjectId `json:"issuedby_userid" bson:"issuedby_userid"`
    ChangedFieldName     string        `json:"changed_field_name,omitempty" bson:"changed_field_name,omitempty"`
    NewChangedFieldValue string     `json:"new_changed_field_value,omitempty" bson:"new_changed_field_value,omitempty"`
    EventType            UserEventType `json:"user_event_type" bson:"user_event_type"`
}

Notice the omitempty on the fields that are optional depending on the type of event.

You really aren't supposed to store different objects in the same collection. Here's a line from the Mongo documentation:

> MongoDB stores documents in collections. Collections are analogous to tables in relational databases.

In case you aren't familiar with relational databases, a table would essentially represent one type of object.

huangapple
  • 本文由 发表于 2017年5月23日 20:28:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/44134844.html
匿名

发表评论

匿名网友

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

确定