Categories
Mastering Development

How do I use bson.SetBSON or bson.Raw?

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

I have a struct like so:

type Game struct {
    ID       bson.ObjectId
    Type     string
    Location string
    Details  interface{}
}

type FeudDetails struct {
    ...
}

type TriviaDetails struct {
    ...
}

type BingoDetails struct {
    ...
}

I want to use the Type field of Game to unserialize Details into a specific type (like an instance of FeudDetails or BingoDetails). It would still be an interface{} in Game, but then I could do this:

feudDetails, ok := game.Details.(FeudDetails)
if ok {
    // we know this is a Feud game, and we have the details
    feudDetails.Round++
}

The docs say that “it is possible to unmarshal or marshal values partially” using bson.Raw, but they don’t provide any examples I’ve been able to find.

I’ve tried using:

func (game *Game) SetBSON(r bson.Raw) error {
    err := r.Unserialize(game)
    if err != nil {
        return nil
    }
    games[game.Type].LoadDetails(game)  // this calls a function based on the Type to
                                        // create a concrete value for that game.
    return nil
}

I get a (ahem) stack overflow here. I assume this is because r.Unserialize is recursively calling SetBSON.

My goal is to use standard unserializing on all fields except Details, and then be able to use game.Type to determine how to process Details. If I do something like this:

type GameDetails interface{}

type Game struct {
    ...
    Details GameDetails
}

func (details *GameDetails) SetBSON(r bson.Raw) error {
    // game isn't defined
    games[game.Type].LoadDetails(r, details)
}

then how can I access the outer Type field to know which game type to unserialize it to?

I’ll also accept the answer “you’re doing it all wrong, and a better pattern in Go is XYZ…”

Leave a Reply

Your email address will not be published. Required fields are marked *