Custom struct type unmarshal

I’m trying to use a custom struct in my mongo object definition but stuck with Marshal\Unmarshal BSON.

type URL struct {
    Uri string
}

type MyStruct struct {
    Image URL `bson:"image"`
}

func (m *URL) UnmarshalBSON(data []byte) error {
    var r bson.Raw
    if err := bson.Unmarshal(data, &m); err != nil {
        return err
    }
    log.Printf("%+v", r.String()) // An empty string
    return nil
}

Unmarshal alway returns an empty field.

Here is an example playground

P.S. The database is legacy and I’m unable to change a scheme, I’m trying to migrate from old mgo driver to official mongo-driver .

Hi @Philidor_Green,

One thing I notice in your example is that UnmarshalBSON internally calls bson.Unmarshal(data, &m) rather than bson.Unmarshal(data, &r). The next line tries to print out the contents of r, but it’s only been set to the zero-value in the variable declaration, so it will be an empty string.

Can you provide some example input/output to show your desired data format? We can help you write Marshal/Unmarshal implementations to do that.

– Divjot

1 Like

Hey @Divjot_Arora,

Yeah an example is little broken, what I need is to use a struct as field

Here is another example. https://play.golang.org/p/eoTK0QuYUaz

type URL struct {
	Uri    string
	Prefix string
}

type MyStruct struct {
	Image URL `bson:"image"`
}

And desired output saved to db:

{
  image: "somestring here"
}

But instead I’ve:

{
  image: {
    uri: "somestring here",
    prefix: ""
  }
}

With old mgo driver I’ve SetBSON\GetBSON which have desired behaivour.

Thanks

Thanks for the example output. This is a little more complex in the driver, but you can use the ValueMarshaler and ValueUnmarshaler interfaces to do this. I’ve written up some example code at https://play.golang.org/p/bVkNezW86Jw.

If you’re doing an mgo to driver migration, you might be interested in looking at the mgo-compatible BSON registry we’ve written, which offers support for interfaces similar to mgo’s Getter and Setter. See https://pkg.go.dev/go.mongodb.org/mongo-driver/bson/mgocompat?tab=doc for some more information about this BSON registry. If you want to try using it, you can add this line to your mongo.Client construction to enable it everywhere:

// You can also use mgocompat.RegistryRespectNilValues for a registry
// that's compatible with mgo's RespectNilValues behavior
clientOpts := options.Client().SetRegistry(mgocompat.Registry)
client, err := mongo.Connect(ctx, clientOpts)

– Divjot

2 Likes

@Divjot_Arora, I was searching for a way to marshal/unmarshal UUID manually and your playground helped me.

TY

2 Likes

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.