I am using Golang/Fiber + Mongo driver.
I have simple struct for blog post:
type Post struct {
ID primitive.ObjectID `json:"_id" bson:"_id,omitempty"`
Title *string `json:"title" bson:"title"`
Slug *string `json:"slug" bson:"slug"`
Content []interface{} `json:"content" bson:"content,omitempty"` // same as any[]
CreatedAt time.Time `json:"created_at" bson:"created_at"`
UpdatedAt time.Time `json:"updated_at" bson:"updated_at"`
PublishedAt *time.Time `json:"published_at" bson:"published_at"`
}
In content I put array of objects:
[
{
data: 'blah blah'
},
{
data: 'blah blah'
}
]
Method itself is pretty straightforward:
func GetPostBySlug(slug string) (Post, error) {
post := Post{}
filter := bson.M{
"slug": slug,
}
database, error := Database.GetMongoDatabase()
if error != nil {
println(error)
}
collection := database.Collection(model_name)
err := collection.FindOne(ctx, filter).Decode(&post)
if err != nil {
return post, err
}
return post, nil
}
And this is what I get:
"_id": "000000000000000000000000",
"title": "Test",
"slug": "test",
"content": [ // array of arrays? what??
[
{
"Key": "data",
"Value": "blah blah"
},
{
"Key": "data",
"Value": "blah blah"
},
]
],
"created_at": "2022-06-07T21:08:04.261Z",
"updated_at": "2022-07-20T21:42:36.717Z",
"published_at": null
In mongodb the content field is saved exactly as I passed it, but when I am trying to get the document, the content transforms to this weird array of arrays with key-value pairs.
If I save something like:
content: [
{
data: {
test: 'test',
what: 'what'
}
}
]
It will transform to this:
content: [
[
Key: "data",
Value: [
{
Key: "test",
Value: "test"
},
{
Key: "what",
Value: "what"
},
]
]
]
I understand the reasons behind this (this is just golang’s way to handle JSON?) and assume there should be an extra step somewhere in the middle, but I have no idea what exactly I need to do
3
Answers
Modify type of
Content
tointerface{}
or juststring
.The reason for what you see is because you use
interface{}
for the element type ofContent
:If you use
interface{}
, it basically carries no type information what type the driver should use when umarshaling the array elements, so the driver will choose / usebson.D
to represent the documents of thecontent
field.bson.D
is a slice that holds the ordered list of fields of the documents, that’s why you see an "array of arrays". Eachbson.D
is a slice, representing a document.If you can model the array elements with a struct, use that, e.g.:
If you don’t have a fixed model for the array elements, alternatively you may use
bson.M
which is a map (but the fields / properties will be unordered which may or may not be a problem):Using it:
@icza is correct. However, only use []bson.M if it’s an array…I had to use bson.M instead because of the structuring of my data.