I am trying to insert the data and read that data from mongodb using mongo go driver. I am using a struct which has a data field. When I am using the data type as interface I get multiple maps and when I specify it as slice of maps it returns a single map. The data is similar in mongodb.
package main
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type Host struct {
Hostname string `bson:"hostname"`
Data []map[string]interface{} `bson:"data"` //return single map
// Data interface{} `bson:"data"` //returns multiple maps
}
func main() {
// Set up a MongoDB client
clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
client, err := mongo.Connect(context.Background(), clientOptions)
if err != nil {
panic(err)
}
// Set up a MongoDB collection
collection := client.Database("testdb").Collection("hosts")
// Create a host object to insert into the database
host := Host{
Hostname: "example.com",
Data: []map[string]interface{}{
{"key1": "using specific type", "key2": 123},
},
}
// Insert the host object into the collection
_, err = collection.InsertOne(context.Background(), host)
if err != nil {
panic(err)
}
// Query the database for the host object
filter := bson.M{"hostname": "example.com"}
var result Host
err = collection.FindOne(context.Background(), filter).Decode(&result)
if err != nil {
panic(err)
}
// Print the host object
fmt.Println(result)
}
Data stored is similar in both cases.
Why there is difference in data when we are trying to access it?
When you use interface{}
, that means you leave it up to the driver to choose any data type it sees best to represent the data that arrives from MongoDB.
When you use []map[string]interface{}
, you explicitly say you want a slice of maps, where each map can represent a document.
When you use interface{}
, you say nothing. The driver will choose bson.A
to represent arrays, and bson.D
to represent documents.
bson.A
is simply a []interface{}
, and bson.D
is []E
where E
is
type E struct {
Key string
Value interface{}
}
So basically bson.D
is an ordered list of key-value pairs (properties).
So when you use interface{}
, you get a slice of slices, not multiple maps. Type information is not printed, the fmt
package prints slices and maps both enclosed in square brackets.
If you want to see the types, print it like this:
fmt.Printf("%#v\n", result.Data)
Output when using []map[string]interface{}
:
[]map[string]interface {}{map[string]interface {}{"key1":"using specific type", "key2":123}}
Output when using interface{}
:
primitive.A{primitive.D{primitive.E{Key:"key1", Value:"using specific type"}, primitive.E{Key:"key2", Value:123}}}