MongoDB-CRUD operations


Working with mongo driver in Go

MongoDB now has official driver available for Go https://github.com/mongodb/mongo-go-driver Usage is pretty straightforward with minor Go modifications othewise is close to the actual shell commands.

Connecting to database

Database connections follow the standard uri syntax for mongo connections

mongodb://<mongoUser>:<mongoPwd>@<mongoHost>

Sample program to initiate a connection

import (
	"context"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

var(
    DbClient             *mongo.Client
	Database             *mongo.Database
)


func InitializeMongoParams() error {
	mongoHost := "localhost:port"
	mongoDb := "databaseName"
	mongoUser := "mongouser"
	mongoPwd := "mongopassword"

	uri := "mongodb://" + mongoUser + ":" + mongoPwd + "@" + mongoHost

	// Set client options
	clientOptions := options.Client().ApplyURI(uri)
	var err error

	// Connect to MongoDB
	DbClient, err = mongo.Connect(context.TODO(), clientOptions)

	if err != nil {
		return err
	}

	// Check the connection
	err = DbClient.Ping(context.TODO(), nil)

	if err != nil {
		return err
	}

    // Select the database to work with
	Database = DbClient.Database(mongoDb)

	return nil
}

CRUD operations

For the rest of the tutorial we can use the sample json and equivalent Go struct below for mongo operations.

{
  "name":"productname",
  "description": "product description",
  "tags":[
      {
        "tagId":"tagOne",
        "tagDesc":"tag one description"
      },
      {
        "tagId":"tagTwo",
        "tagDesc":"tag two description"
      }
    ]
}
type Product struct {
    Name        string `json:"name"`
    Description string `json:"description"`
    Tags        []*Tag  `json:"tags"`
}

type Tag struct {
    TagID   string `json:"tagId"`
    TagDesc string `json:"tagDesc"`
}

Inserting a document

Mongo driver accepts Go structs as document model and can be passed as reference to InsertOne or InsertMany commands. Any type that requires null can be assigned as Go nil values. So it makes sense to model types as pointer in document struct model.

func InsertProduct(ctx context.Context, product *Product) error {
	inserted, err := Database.Collection("products").InsertOne(ctx, user)
	if err != nil {
		return err
	}
	log.Printf("inserted id =%v", inserted.InsertedID)
	return nil
}

Updating a document

Replace/Update whole document

Updating entire document don’t require a $set or any other command. Instead the whole document can be passed to bson document model.

func UpdateProduct(ctx context.Context, product *Product) error {
	_, err = Database.Collection("products").UpdateOne(ctx,
		bson.M{"name": product.Name},
		bson.D{
			{"$set", product},
		},
	)
	if err != nil {
		return err
	}
	return nil
}
Updating fields in a document

We can update collections and fields in document using typical $set commands. Below example the matching array and a normal field in document can be updated.

func UpdateProduct(ctx context.Context, tag *Tag, name string) error {
	_, err := Database.Collection("products").UpdateOne(ctx,
		bson.M{"name": name, "tags.tagId": tag.TagID},
		bson.D{
			{"$set", bson.D{
				{"tags.$", tag},
				{"description", "new description"},
			}},
	})
	if err != nil {
		return err
	}
	return nil
}

If we need to push an element to existing array. This will fail if the existing value is null.

func UpdateProduct(ctx context.Context, tag *Tag, name string) error {
	_, err = Database.Collection("products").UpdateOne(ctx,
			bson.M{"name": name},
			bson.D{
				{"$push", bson.D{
					{"tags", tag},
				}},
				{"$set", bson.D{
					{"description", "new desc"},
				}},
			})
	if err != nil {
		return err
	}
	return nil
}

Querying documents

Documents can be queried by passing BSON document or BSON map

Using FindOne
product := Product{}
err := Database.Collection("products").
	FindOne(ctx, bson.M{"name": name}).
	Decode(&product)

Querying using collection fields

product := Product{}
err := Database.Collection("products").
	FindOne(ctx, bson.M{
		"$and": []bson.M{
			bson.M{"tags.tagId": tagId},
			bson.M{"tags.tagDesc": tagDesc},
		},
	}).
	Decode(&product)