2014-09-25 108 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 
}