Search code examples
jsonmongodbgomongo-go

Dump a mongodb array of objects in a slice of struct


I have an array of objects along with other fields in a mongodb document:

db.config.find({},{list_attributes:1, _id:0});
[
{
    list_attributes: {
    '0': { field: 'LASTNAME', field_key: 'lastname', dataType: 'text' },
    '1': { field: 'FIRSTNAME', field_key: 'firstname', dataType: 'text' },
    '2': { field: 'SMS', dataType: 'text' },
    '3': {
        field: 'DOUBLE_OPT-IN',
        dataType: 'category',
        order: 1,
        catAttrib: { '1': 'Yes', '2': 'No' }
    },
    '4': { field: 'OPT_IN', dataType: 'boolean', order: 2 },
    '5': { field: 'TEST_NUMBER', dataType: 'float', order: 3 },
    '6': { field: 'TEST_DATE', dataType: 'date', order: 4 }
    }
}
]

I want to dump this data in a slice of the following struct so that 0th index of slice contains the 0th object of list_attributes array:

type MongoFields struct {
    Field     string `bson:"field" json:"field"`
    FieldKey  string `bson:"field_key,omitempty" json:"field_key,omitempty"`
    DataType  string `bson:"data_type" json:"data_type"`
    Order     int    `bson:"order,omitempty" json:"order,omitempty"`
    CatAttrib bson.M `bson:"catAttrib,omitempty" json:"catAttrib,omitempty"`
}

I am using the official mongodb driver for golang.

package main

import (
    "context"       // manage multiple requests
    "encoding/json" // Use JSON encoding for bson.M string
    "fmt"           // Println() function
    "log"
    "reflect" // get an object type

    // import 'mongo-go-driver' package libraries
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

type MongoFields struct {
    Field     string `bson:"field" json:"field"`
    FieldKey  string `bson:"field_key,omitempty" json:"field_key,omitempty"`
    DataType  string `bson:"data_type" json:"data_type"`
    Order     int    `bson:"order,omitempty" json:"order,omitempty"`
    CatAttrib bson.M `bson:"catAttrib,omitempty" json:"catAttrib,omitempty"`
}

func main() {

    // Declare host and port options to pass to the Connect() method
    clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")

    // Connect to the MongoDB and return Client instance
    client, err := mongo.Connect(context.TODO(), clientOptions)
    if err != nil {
        fmt.Println("mongo.Connect() ERROR:", err)
        log.Fatal(err)
    }

    // Declare Context object for the MongoDB API calls
    ctx := context.Background()

    // Access a MongoDB collection through a database
    col := client.Database("SomeDatabase").Collection("Some Collection")

    // Typical BSON Map filter
    //filter := bson.M{"int field": bson.M{"$gt":42}}

    // Create a string using ` string escape ticks
    query := `{list_attributes:1, _id:0}`

    // Declare an empty BSON Map object
    var bsonMap bson.M

    // Use the JSON package's Unmarshal() method
    err = json.Unmarshal([]byte(query), &bsonMap)
    if err != nil {
        panic(err)
    } else {
        fmt.Println("bsonMap:", bsonMap)
        fmt.Println("bsonMap TYPE:", reflect.TypeOf(bsonMap))
    }

    // Nest the Unmarshalled BSON map inside another BSON object
    filter := bson.M{"field": bsonMap}

    // Pass the filter to Find() to return a MongoDB cursor
    cursor, err := col.Find(ctx, filter)
    if err != nil {
        log.Fatal("col.Find ERROR:", err)
    }

    // Print cursor object
    fmt.Println("\ncursor TYPE:", reflect.TypeOf(cursor))
    fmt.Println("cursor:", cursor)

    // iterate through all documents
    for cursor.Next(ctx) {
        var p MongoFields

        // Decode the document
        if err := cursor.Decode(&p); err != nil {
            log.Fatal("cursor.Decode ERROR:", err)
        }
        // Print the results of the iterated cursor object
        fmt.Printf("\nMongoFields: %+v\n", p)
    }
}

I am getting:

panic: invalid character 'l' looking for beginning of object key string

goroutine 1 [running]:
main.main()
    /home/arun/GolandProjects/storeInSlice/main.go:54 +0x6c5

Solution

  • Your query JSON is not valid JSON:

    // Create a string using ` string escape ticks
    query := `{list_attributes:1, _id:0}`
    
    // Declare an empty BSON Map object
    var bsonMap bson.M
    
    // Use the JSON package's Unmarshal() method
    err = json.Unmarshal([]byte(query), &bsonMap)
    

    A valid JSON would be:

    query := `{"list_attributes":1, "_id":0}`
    

    But it's much simpler to use a composite literal to create such projection:

    query := bson.M{
        "list_attributes": 1,
        "_id":             0,
    }
    

    And this is a document to define projection (list fields you want to retrieve). This should not be the same as the filter document.

    To fetch all documents without a filter, use an empty document, e.g.:

    filter := bson.D{}
    // or 
    filter := bson.M{}