I am writing a multilingual API with go and mongodb. I have a mongo db document with format:
{
_id : ObjectID(bla)
"key" : {
"en" : "Hello",
"es" : "Hola"
}
}
However, the API needs report json in the form:
{
_id : ObjectID(bla),
"key" : "Hola"
}
if the client sends language headers.
Is there an easy/efficent way to do this? The only working solution I have is to make two separate structs and then merge them together with a bunch of switch/case statements, like:
var api MyStruct
var mgo MyMgoStruct
session.DB("db").C("col").Find(nil).One(&mgo)
api.ID = mgo.ID
switch lang {
default:
{
api.Key = string(mgo.Key.En)
}
case "es":
{
api.Key = string(mgo.Key.Es)
}
}
Structure defs:
type Translation struct {
En string `bson:"en"`
Es string `bson:"es"`
}
type MyStruct struct {
ID bson.ObjectID `json:"_id" bson:"_id"`
Key string `json:"key" bson:"key"`
}
type MyMgoStruct struct {
ID bson.ObjectID `json:"_id" bson:"_id"`
Key Translation `json:"key" bson:"key"`
}
I foresee this becoming a huge pain to maintain, as my structures have tens of translated fields. I would prefer a way to transform the MongoDB document, replacing the Translation json structure with a simple key-value pair as in the MyStruct struct.
The only working solution I have is to make two separate structs and then merge them together with a bunch of switch/case statements
An alternative is you could use MongoDB projection on the Find(). Given your example document format, for example:
// Client input language header as variable
var languageInput = "es"
// Concatenate to get field nest 'key'
key := "key." + languageInput
// Only project the specific fields
cursor := coll.Find(nil).Select(bson.M{key: 1})
See also Project fields to return from query
If you have many translation fields in your struct that you don't want to map, you could utilise bson inline
. For example:
type MyStruct struct {
ID bson.ObjectId `json:"id" bson:"_id"`
OtherFields bson.M `bson:",inline"`
}
This would capture unstructured fields in OtherFields
. See also bson.Marshal