[GODRIVER-890] Error on Marshal method of a struct Created: 20/Mar/19  Updated: 11/Sep/19  Resolved: 02/Apr/19

Status: Closed
Project: Go Driver
Component/s: BSON
Affects Version/s: 1.0.0
Fix Version/s: None

Type: Task Priority: Major - P3
Reporter: Rafael Souza Assignee: Kristofer Brandow (Inactive)
Resolution: Done Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Linux Ubuntu 16.4



 Description   

I've made some tests implementing the `Marshaler` and `ValueMarshaler` interfaces, but any of then I was able to make it work. I always get a error similar to this:

(mongo.MarshalError) cannot transform type map[string]interface {} to a BSON Document: WriteString can only write while positioned on a Element or Value but is positioned on a TopLevel

 
I wrote a test which points exactly to the problem:

package main
 
import (
	"context"
	"time"
 
	"github.com/davecgh/go-spew/spew"
 
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/bsontype"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)
 
var (
	client   *mongo.Client
	database *mongo.Database
	ctx      context.Context
)
 
type MyValue struct {
}
 
func (m MyValue) MarshalBSONValue() (bsontype.Type, []byte, error) {
	b, err := bson.Marshal(`fixed value`)
	if err != nil {
		return bsontype.String, nil, err
	}
 
	return bsontype.String, b, err
}
 
// func (m MyValue) MarshalBSONValue() (bsontype.Type, []byte, error) {
// 	return bsontype.String, []byte(`fixed value`), nil
// }
 
type MyOtherValue struct {
}
 
func (m MyOtherValue) MarshalBSON() ([]byte, error) {
	return bson.Marshal(`fixed value`)
}
 
// func (m MyOtherValue) MarshalBSON() ([]byte, error) {
// 	return []byte(`fixed value`), nil
// }
 
func main() {
	defer disconnect()
 
	connect()
 
	insert()
}
 
func insert() {
	test1 := map[string]interface{}{
		"value1": "test 1",
		"value2": MyValue{},
		"value3": MyOtherValue{},
	}
 
	res, err := database.Collection("encoding").InsertOne(ctx, test1)
 
	spew.Dump(res, err)
}
 
func read() {
	response := map[string]interface{}{}
 
	res := database.Collection("encoding").FindOne(ctx, bson.M{})
	res.Decode(&response)
 
	spew.Dump(response)
}
 
func connect() {
	var err error
 
	ctx, _ = context.WithTimeout(context.Background(), 30*time.Second)
	clientOptions := []*options.ClientOptions{
		options.Client().ApplyURI("localhost:27017"),
	}
 
	client, err = mongo.Connect(ctx, clientOptions...)
	if nil != err {
		panic(err)
	}
 
	database = client.Database("test")
}
 
func disconnect() {
	if client != nil {
		client.Disconnect(ctx)
	}
}

Is there any problem with my implementation or is actually a bug?



 Comments   
Comment by Kristofer Brandow (Inactive) [ 02/Apr/19 ]

Hi souzasrafael, that's the correct solution.

--Kris

Comment by Rafael Souza [ 01/Apr/19 ]

I figured out how to make it works:

func (m MyValue) MarshalBSONValue() (bsontype.Type, []byte, error) {
   return bsontype.String, bsoncore.AppendString(nil, `fixed value`), nil
}

Thanks!

Comment by Rafael Souza [ 21/Mar/19 ]

Ian,

I did a test using the value marshaler, too:

func (m MyValue) MarshalBSONValue() (bsontype.Type, []byte, error) {
	b, err := bson.Marshal(`fixed value`)
	if err != nil {
		return bsontype.String, nil, err
	}
 
	return bsontype.String, b, nil
}

And get the same error:

(mongo.MarshalError) cannot transform type map[string]interface {} to a BSON Document: WriteString can only write while positioned on a Element or Value but is positioned on a TopLevel

So, how can I use the value marshaler correctly? Also, I did a test trying to create a byte array instead of using the bson.Marshal function:

func (m MyValue) MarshalBSONValue() (bsontype.Type, []byte, error) {
	return bsontype.String, []byte(`fixed value`), nil
}

Got the error:

(bsoncore.InsufficientBytesError) too few bytes to read next component

Comment by Ian Whalen (Inactive) [ 21/Mar/19 ]

Hey souzasrafael - as per your line here:

{{ return bson.Marshal(`fixed value`)}}

You can't actually marshal a string, you'll need to use a value marshaler instead.

Comment by Diego Marangoni [ 20/Mar/19 ]

I'm having the same issue. I can decode normally, but can't encode it

Generated at Thu Feb 08 08:35:11 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.