Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Source data must be an array or slice, got string #309

Open
zhangchiyue opened this issue Oct 19, 2022 · 2 comments
Open

Source data must be an array or slice, got string #309

zhangchiyue opened this issue Oct 19, 2022 · 2 comments

Comments

@zhangchiyue
Copy link

zhangchiyue commented Oct 19, 2022

When i try decode a map[string]interface {} into stuct the error return "Source data must be an array or slice, got string".
This is the code :

func main() {
	id, _ := primitive.ObjectIDFromHex("62295b0650935306baee588c")
	source := &Person{
		Name: "Lucy",
		Data: &User{
			Username: "Luck",
			Uid:      id,
		},
	}
	bytes, _ := json.Marshal(source)
	target := &Person{}
	json.Unmarshal(bytes, target)
	fmt.Printf("%T\n", target.Data)
	result := &User{}
	config := mapstructure.DecoderConfig{
		Result:  result,
		TagName: "json",
	}
	decoder, _ := mapstructure.NewDecoder(&config)
	err := decoder.Decode(target.Data)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("%+v", result)
}

type User struct {
	Username string             `json:"username"`
	Uid      primitive.ObjectID `json:"uid"`
}

type Person struct {
	Name string `json:"name"`
	Data any    `json:"data"`
}

The error message is "* 'uid': source data must be an array or slice, got string"

@ArkjuniorK
Copy link

I think that's because the primitive.ObjectID type is a an array of byte but when it decode from map the given type was string.

@ArkjuniorK
Copy link

You could add DecodeHook with given syntax, it would check the type both of destination type and origin type since ObjectID is an array we set the destination type to array if it match then convert the data to string and generate new ObjectID with it. Hopes it help!

DecodeHook: func(from, to reflect.Type, d interface{}) (interface{}, error) {
	if from.Kind() == reflect.String && to.Kind() == reflect.Array {
		sid := d.(string)
		id, err := primitive.ObjectIDFromHex(sid)
		if err != nil {
			fmt.Println(err)
		}

		d = id
	}

	return d, nil
},

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants