2014-09-25 46 views
4

假设您有一个由多个不同类型的嵌入式节点组成的工作流程。由于节点是不同类型的,我想在这里使用Golang接口,并与下面上来:如何在mgo(Go)中使用界面类型作为模型?

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 
} 

这些工作流程都存储在MongoDB中,我有它的样本种子数据。使用氧化镁,当我试图找到一个工作流程(鉴于其ID):

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

我得到的错误 - 类型bson.M的价值是不能分配给类型的节点。

这对我来说也感觉有点奇怪,如何将mgo解组嵌入到没有任何类型信息的Go结构中。可能是我需要从另一个角度来看问题。

任何建议将不胜感激。

回答

5

由于您记下的原因,您无法在文档中使用接口。解码器没有关于要创建的类型的信息。处理这种

的一种方法是定义一个结构来保存类型的信息:

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

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

实现这种类型的SetBSON功能。该函数应解码字符串类型,根据该字符串创建一个正确类型的值并解组为该值。

func (nt *NodeWithType) SetBSON(r bson.Raw) error { 
} 
+0

太棒了!这样可行。整齐。 – shardnit 2014-09-25 19:10:14

+0

你可以举一个setBSON函数如何实现的例子吗?我不知道如何解码字符串。 – e3matheus 2017-09-19 16:45:15

1

继西蒙福克斯关于实施SetBSON的回答,这里有一个更准确的答案。

让我们原来的代码:

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 
} 

你想现在做的是:一旦你从蒙戈解编BSON对象,你要能够知道每个节点是一个EmailNodeTwitterNode

由于您正在将节点存储为Node接口,因此mgo无法知道要实施哪个结构,因此您必须明确告知它。这里来了SetBSON

在你的例子中,问题来自于这个Workflow.Nodes,它是一个Node接口片。由于这是一个简单的片,最好是你创建的MgO就能解编BSON时调用自定义类型:

type NodesList []Node 

// The updated Workflow struct: 
type Workflow struct { 
    CreatedAt time.Time 
    StartedAt time.Time 
    CreatedBy string 
    Nodes  NodesList 
} 

现在,你可以在此NodesList实施SetBSON并说明它是如何工作。请注意,当您使用指针时,您可以定义变量内包含的内容:

// Note that you must use a pointer to the slice 
func (list *NodesList) SetBSON(raw raw.BSON) error { 
    // Now you need to create the objects according to your 
    // own domain logic and what's contained inside "raw": 
    if raw.something { 
     *list = append(*list, &TwitterNode{}) 
    } else { 
     *list = append(*list, &EmailNode{}) 
    } 

    return nil 
}