Convert data from mongo to struct

xuanbao · 2017-11-17 07:00:13 · 808 次点击    
这是一个分享于 2017-11-17 07:00:13 的资源,其中的信息可能已经有所发展或是发生改变。

Hi all,

I am working on a small side project to learn go and I have hit an issue that hours of Googling and trying have made no impact on for me.

I am storing records in mongodb via mgo, which works fine. I can pull records from mongo and send JSON perfectly.

However when I try to convert the data from mongo back into concrete types I am "missing" data that implements the "Alert" interface.

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/credentials"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/sns"
    mgo "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
)

type Alert interface {
    Send(message string) error
}

type EndPoint struct {
    Name          string         `json:"name" bson:"name"`
    URI           string         `json:"uri" bson:"uri"`
    Method        string         `json:"method" bson:"method"`
    IgnoreSSL     bool           `json:"ignoreSsl" bson:"ignoreSsl"`
    CheckInterval string         `json:"checkInterval" bson:"checkInterval"`
    LastStatus    bool           `json:"lastStatus" bson:"lastStatus"`
    Headers       http.Header    `json:"headers" bson:"headers"`
    Alerts        []Alert `json:"alerts" bson:"alerts"`
}

type ConsoleAlert struct {
    Type string `json:"type" bson:"type"`
}

func (ca ConsoleAlert) Send(message string) error {
    log.Println(message)
    return nil
}

type SNSAlert struct {
    Type     string `json:"type" bson:"type"`
    Region   string `json:"region" bson:"region"`
    Key      string `json:"key" bson:"key"`
    Secret   string `json:"secret" bson:"secret"`
    TopicARN string `json:"topic_arn" bson:"topic_arn"`
}

func getSession(sa SNSAlert) (*session.Session, error) {
    sess, err := session.NewSession(&aws.Config{
        Region:      aws.String(sa.Region),
        Credentials: credentials.NewStaticCredentials(sa.Key, sa.Secret, ""),
    })

    if err != nil {
        return &session.Session{}, err
    }

    return sess, nil
}

func (sa SNSAlert) Send(message string) error {

    sess, err := getSession(sa)
    if err != nil {
        return err

    }
    svc := sns.New(sess)

    params := &sns.PublishInput{
        Message:  aws.String(message),
        TopicArn: aws.String(sa.TopicARN),
    }

    _, err = svc.Publish(params)

    if err != nil {
        return err
    }

    return nil
}

func main() {

    session, err := mgo.Dial("localhost")
    if err != nil {
        panic(err)
    }
    defer session.Close()
    DB := session.DB("mogon")
    COL := DB.C("serverstest")

    var bsonEPs []bson.M
    err = COL.Find(bson.M{}).All(&bsonEPs)
    if err != nil {
        fmt.Println(err)
    }
    jsonResp, merr := json.Marshal(bsonEPs)
    if merr != nil {
        fmt.Println(err)
    }

    // We can get the data just fine as JSON
    fmt.Printf("\nJSON DATA\n")
    fmt.Println(string(jsonResp))

    var endpoints []interface{}
    json.Unmarshal(jsonResp, &endpoints)
    fmt.Printf("\nSTRUCT DATA\n")
    fmt.Println(endpoints)

    // mgo can't Find into a slice of EndPoints
    var bsonEPsAttempt = make([]EndPoint, 10)
    err = COL.Find(bson.M{}).All(&bsonEPsAttempt)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(bsonEPsAttempt)

}

Below is the console output when trying to get EndPoints

JSON DATA
[{"_id":"5a0e42ab26d6291543f2128b","alerts":[{"type":"console"},{"key":"AWS KEY","region":"us-east-1","secret":"AWS SECRET","topic_arn":"arn:aws:sns:us-east-1:424242:alert","type":"sns"}],"checkInterval":"14s","headers":{"authKey":["password"]},"ignoreSsl":false,"lastStatus":false,"method":"GET","name":"myserver","uri":"https://myapp.com/check"}]

STRUCT DATA
[map[alerts:[map[type:console] map[key:AWS KEY region:us-east-1 secret:AWS SECRET topic_arn:arn:aws:sns:us-east-1:424242:alert type:sns]] headers:map[authKey:[password]] lastStatus:false method:GET uri:https://myapp.com/check _id:5a0e42ab26d6291543f2128b checkInterval:14s ignoreSsl:false name:myserver]]

[]EndPoint FAIL
reflect.Set: value of type bson.M is not assignable to type alerts.Alert
[]

How can I reliably create an EndPoint?


评论:

Kraigius:

Umm..you didn't post the struct for alerts.Alert and can you post a minimal repro case?

xandout:

I have edited the code above, alerts.Alert is now Alert

Kraigius:

Thanks. I admit that I didn't try your code but I have a better understanding of it now. I found one thread on stackoverflow that seems to suggest that it's not possible without a workaround but I'll keep looking.

https://stackoverflow.com/questions/26039580/how-to-use-interface-type-as-a-model-in-mgo-go

edit: related?

xandout:

Ended up with a less than elegant solution involving a switch and json marshalling.

Thanks for the tips


入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

808 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传