'Marshal into a bson.Raw

Using gopkg.in/mgo.v2/bson, I wonder how to marshal an interface{} value into a value of type bson.Raw.

The documentation for bson.Raw states:

Using this type it is possible to unmarshal or marshal values partially.

But I can't find a Marshal function that would return bson.Raw.

What am I missing?

Example of what I try to do:

package main

import (
    "fmt"

    "gopkg.in/mgo.v2/bson"
)

func main() {
    // How to avoid a MarshalRaw help function?
    raw, err := MarshalRaw("Hello world")
    if err != nil {
        panic(err)
    }

    fmt.Printf("%+v\n", raw)
}

func MarshalRaw(v interface{}) (*bson.Raw, error) {
    bin, err := bson.Marshal(struct{ Raw interface{} }{v})
    if err != nil {
        return nil, err
    }

    var raw struct{ Raw bson.Raw }
    err = bson.Unmarshal(bin, &raw)
    if err != nil {
        return nil, err
    }

    return &raw.Raw, nil
}

Output:

&{Kind:2 Data:[12 0 0 0 72 101 108 108 111 32 119 111 114 108 100 0]}



Solution 1:[1]

bson.Raw is used as a value both when marshaling and unmarshaling.

To transform an interface{} into a bson.Raw, the first thing to do is to marshal it so that you get the plain document data that represents whatever is being marshaled:

    var value interface{} = bson.M{"some": "value"}
    data, err := bson.Marshal(value)
    if err != nil {
            log.Fatal(err)
    }

and then it may have one or more fields unmarshaled into bson.Raw values:

    var doc struct{ Some bson.Raw }
    err = bson.Unmarshal(data, &doc)
    if err != nil {
            log.Fatal(err)
    }

or even the entire document:

    var doc bson.Raw
    err = bson.Unmarshal(data, &doc)
    if err != nil {
            log.Fatal(err)
    }

If you want the entire document rather than just a field, you can also use this shortcut:

    doc := bson.Raw{3, data}

The 3 constant represents a document in the bson specification, and it must of course match the provided data. Since BSON only supports documents at the top level, we know this must be correct.

Solution 2:[2]

I believe that bson.Raw is intended to be used as a type for a variable.

for example: (in play)

type Bar struct {
   AnInt int
   AString bson.Raw
}

The "AString" field will be kept as the bson.Raw struct your link mentions.

This is super-useful if you want to partially decode the top level of a nested structure to figure out its actualy type so you can parse the rest in to the proper datatype.

Note, the above is untested, not in front of a machine I can actually run go on at the moment. This is based on the assumption that it works like the standard encoding/json package.

Solution 3:[3]

Solution I was looking for

m := bson.M{"ns": bson.M{"coll": "test1", "db": "testdb"}}
data, _ := bson.Marshal(m)
r := bson.Raw(data)
coll := r.Lookup("ns", "coll").StringValue()
println(coll)

Playground

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Gustavo Niemeyer
Solution 2 David Budworth
Solution 3 okharch