Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use interface type as a model in mgo (Go)?

Tags:

mongodb

go

mgo

Suppose you have a workflow that consists of multiple embedded nodes of different types. Since nodes are of different types, I thought of using Golang interfaces here and came up with following:

type Workflow struct {
   CreatedAt time.Time
   StartedAt time.Time
   CreatedBy string
   Nodes []Node
}

type Node interface {
  Exec() (int, error)
}

type EmailNode struct {
   From string
   To string
   Subject string
   Body string
}

type TwitterNode struct {
   Tweet string
   Image []byte
}

func (n *EmailNode) Exec() (int, error){
   //send email
   return 0, nil
}

func (n *TwitterNode) Exec() (int, error) {
   //send tweet
   return 0, nil
}

These workflows are stored in MongoDB and I have sample seed data in it. Using mgo, when I try to find a workflow (given its ID):

w = &Workflow{}
collection.FindID(bson.ObjectIdHex(id)).One(w)

I get the error - value of type bson.M is not assignable to type Node.

It also feels a bit weird to me that how would mgo unmarshal embedded Node documents into a Go struct without any type information. May be I need to look at the problem from another point of view.

Any suggestions would be highly appreciated.

like image 257
shardnit Avatar asked Sep 25 '14 13:09

shardnit


People also ask

What are interfaces in go?

One of the core implementations of composition is the use of interfaces. An interface defines a behavior of a type. One of the most commonly used interfaces in the Go standard library is the fmt.Stringer interface:

How to create an interface in Golang?

How to create an interface? In Go language, you can create an interface using the following syntax: type interface_name interface{ // Method signatures } For Example: // Creating an interface type myinterface interface{ // Methods fun1() int fun2() float64 }

How many methods does the stringer interface have in go?

The Stringer interface has only one method, called String () that returns a string. A method is a special function that is scoped to a specific type in Go. Unlike a function, a method can only be called from the instance of the type it was defined on.

What is the difference between struct and interface in go?

Just like defining a struct, Go uses curly braces ( {}) to surround the definition of the interface. In comparison to defining structs, we only define the interface’s behavior; that is, “what can this type do”. In the case of the Stringer interface, the only behavior is the String () method.


1 Answers

You cannot use an interface in a document for the reason you noted. The decoder has no information about the type to create.

One way to handle this is to define a struct to hold the type information:

type NodeWithType struct {
   Node Node `bson:"-"`
   Type string
}

type Workflow struct {
   CreatedAt time.Time
   StartedAt time.Time
   CreatedBy string
   Nodes []NodeWithType
}

Implement the SetBSON function on this type. This function should decode the type string, create a value of the correct type based on that string and unmarshal to that value.

func (nt *NodeWithType) SetBSON(r bson.Raw) error {
}
like image 196
Simon Fox Avatar answered Oct 18 '22 20:10

Simon Fox