Embedding Interfaces in MongoDB Models with mgo
When working with a workflow system that involves nodes of varying types, it's common to use Go interfaces to represent the different node types. However, this approach presents a challenge when storing these workflows in MongoDB using mgo.
Consider the following example:
<code class="go">type Workflow struct { CreatedAt time.Time StartedAt time.Time CreatedBy string Nodes []Node } type Node interface { Exec() (int, error) }</code>
Where Node is an interface with a single method, Exec() that can be implemented by different node types.
To store a workflow in MongoDB, you may attempt to find it by ID:
<code class="go">w = &Workflow{} collection.FindID(bson.ObjectIdHex(id)).One(w)</code>
However, you will encounter an error because mgo cannot unmarshal embedded Node interfaces directly into a Go struct. This is because it lacks the necessary type information to create the appropriate concrete type for each node.
To address this issue, you can define a struct that explicitly holds both the node type and the actual node value:
<code class="go">type NodeWithType struct { Node Node `bson:"-"` Type string } type Workflow struct { CreatedAt time.Time StartedAt time.Time CreatedBy string Nodes []NodeWithType }</code>
By using bson:"-", the Node subfield is excluded from automatic decoding and instead handled manually in the SetBSON function:
<code class="go">func (nt *NodeWithType) SetBSON(r bson.Raw) error { // Decode the node type from the "Type" field // Create a new instance of the concrete node type based on the decoded type // Unmarshal the remaining document into the concrete node type //... }</code>
This approach allows mgo to identify the type of each node and create the appropriate concrete instance during decoding, resolving the type information issue.
The above is the detailed content of How Can You Embed Go Interfaces in MongoDB Models Using mgo?. For more information, please follow other related articles on the PHP Chinese website!