3

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)
}

When only interface is used When only interface is used

When slice of maps is used When slice of maps is used

Data stored is similar in both cases. Data stored is similar in both cases.

Why there is difference in data when we are trying to access it?

R0512S
  • 53
  • 4

1 Answers1

2

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}}}
icza
  • 389,944
  • 63
  • 907
  • 827
  • Thanks for the explaination. I was previously using [mgo driver](https://pkg.go.dev/gopkg.in/mgo.v2), in that I was getting the data as []map[string]interface{} when reading from DB even when specifying interface as type. But now when migrating to mongo driver the data type is getting changed. Is it because of these two drivers work differently? – R0512S Apr 18 '23 at 09:24
  • 1
    @rishabhs-s Yes, as written in my first sentence, it's up to the driver to choose the type if you don't do it (due to using `interface{}`). – icza Apr 18 '23 at 09:39