I want to query data which was inserted by C# mongodriver with polymorhism. The query will be done by Golang driver. Structure of the data is shown below. I want to map _t to structs, in other words, I want to apply polymorhism to record in Go. Is it possible to do it in Golang mongo drivers? The list of structs is below as well.
One record example from mongo collection
{"_id" : "asdasda12312312asdasda",
"structure" : [
{
"_t" : "AObject",
"Text" : "asdasdasda",
"State" : "asdasda"
},
{
"_t" : "BObject",
"Number" : "123",
},
{
"_t" : "CObject",
"Testing" : "Pompeo"
}
]
}
Go Structs
type Data struct{
_id string
Structure []Object
}
type Object interface{
}
type AObject struct {
Text string
State string
}
type BObject struct {
Number string
}
type CObject struct {
Testing string
}
Thanks
What mongo driver are you using? "_t" is a parameter used to determine what type was serialized if the current type is different than the nominal type. It's also used for normal JSON serialization so you have one of three ways I can think of.
type MongoObject struct {
// Contains all fields from all objects
_t string
Text string
State string
Number string
Testing string
}
func DeserializeObject(object MongoObject) Object{
switch t {
case "AObject":
return &AObject{Text: object.Text, State: object.State}
case "BObject":
return &BObject{Number: object.Text}
case "CObject":
return &CObject{Testing: object.Testing}
}
}
Using interfaces generally is problematic, because the libraries doing the unmarshaling would have hard time deciding what type to choose. You could use custom unmarshaler in which you choose the appropriate type, but that's more cumbersome and complex.
Easiest is to use concrete struct types. You have to use struct tags to map between struct fields and fields in the MongoDB documents. One important thing is that in Go fields must be exported else they cannot be populated / read by libraries that do the work. For it to be exported, their name must start with a capital letter, and underscore (_
) isn't one of them.
If the (sub)documents may have different fields based on a value, you may add all, and the ones that are present will be properly unmarshaled.
Your document may be modeled like this:
type Data struct {
ID string `bson:"_id"`
Structure []Object `bson:"structure"`
}
type Object struct {
T string `bson:"_t"`
Text string `bson:"Text,omitempty"`
State string `bson:"State,omitempty"`
Number string `bson:"Number,omitempty"`
Testing string `bson:"Testing,omitempty"`
}
Note that the ,omitempty
option isn't required for unmarshaling, but if you'd want to use these same types for marsaling (e.g. saving a new document), the ,omitempty
option will ensure to leave out fields that are empty.
Also note that if this doesn't satisfy you, there's nothing stopping you to post-process the result. You can switch on the available Object.T
field and create "dynamic" instances of types of your choosing.