preface

Recently, I learned how to operate mongodb in GO, and learned that there are two libraries, third-party MGO and official Mongo-driver, that are used most. Mgo has stopped maintenance, so mongo-driver is selected. This article records some common code operation notes for easy reference.

The installation

#Initialize the go module, named Mongo-Notes
mkdir goMongo && cd goMongo
go mod init mongo-notes

#Get go Mongo module dependencies
go get go.mongodb.org/mongo-driver/mongo
Copy the code

Client connection

There are two main methods for client connection:

  1. New a client instance, then Connect;
  2. Connect directly while obtaining a client instance.

The second method is usually used and the code is more concise.

Any operation on Mongo, including Connect, CURD, Disconnect, etc., is inseparable from the Context Context of an operation, requiring a Context instance as the first parameter of the operation.

Connect using the NewClient instance

package main

import (
  "context"
  "fmt"
  "time"

  "go.mongodb.org/mongo-driver/mongo"
  "go.mongodb.org/mongo-driver/mongo/options"
)

func main(a) {
  client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://localhost:27017"))
  iferr ! =nil {
    fmt.Errorf("client establish failed. err: %v", err)
  }
  // ctx
  ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  defer cancel()

  // connect
  if err = client.Connect(ctx); err == nil {
    fmt.Println("connect to db success.")}// Delay the call to the disconnection function after the client is instantiated
  defer func(a) {
    iferr = client.Disconnect(ctx); err ! =nil {
      panic(err)
    }
  }()
}
Copy the code

Connect using the mongo.connect () function

A direct connection

package main

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

func main(a) {
  clientOpts := options.Client().ApplyURI("mongodb://localhost:27017/? connect=direct")
  client, err := mongo.Connect(context.TODO(), clientOpts)
  iferr ! =nil {
      log.Fatal(err)
  }
}
Copy the code

User name and password authentication connection

package main

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

func main(a) {
  credential := options.Credential{

      Username: "username",
      Password: "password",
  }
  clientOpts := options.Client().ApplyURI("mongodb://localhost:27017").SetAuth(credential)
  // You can connect directly to the URI with the username and password
  // clientOpts := options.Client().ApplyURI("mongodb://username:password@localhost:27017")
  client, err := mongo.Connect(context.TODO(), clientOpts)
  iferr ! =nil {
      log.Fatal(err)
  }
}
Copy the code

ReplicaSet replicas are connected

package main

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

func main(a) {
  clientOpts := options.Client().ApplyURI("mongodb://localhost:27017,localhost:27018/? replicaSet=replset")
  client, err := mongo.Connect(context.TODO(), clientOpts)
  iferr ! =nil {
      log.Fatal(err)
  }
}
Copy the code

Shard Fragment connection

package main

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

func main(a) {
  clientOpts := options.Client().ApplyURI("mongodb://localhost:27017,localhost:27018")
  client, err := mongo.Connect(context.TODO(), clientOpts)
  iferr ! =nil {
      log.Fatal(err)
  }
}
Copy the code

Module configuration type connection

In real projects, there are usually configuration modules, so the most common way to connect is to write the connection configuration in a special configuration module file:

package config

import (
  "time"

  "go.mongodb.org/mongo-driver/mongo/options"
  "go.mongodb.org/mongo-driver/mongo/readpref"
)

// MONGO SETTINGS
var (
  credentials = options.Credential{
    AuthMechanism: "SCRAM-SHA-1",
    AuthSource:    "anquan",
    Username:      "ysj",
    Password:      "123456",}// direct = true
  connectTimeout        = 10 * time.Second
  hosts                 = []string{"localhost:27017"."localhost:27018"}
  maxPoolSize    uint64 = 20
  minPoolSize    uint64 = 5
  readPreference        = readpref.Primary()
  replicaSet            = "replicaSetDb"

  // ClientOpts mongoClient connection client parameters
  ClientOpts = &options.ClientOptions{
    Auth:           &credentials,
    ConnectTimeout: &connectTimeout,
    //Direct: &direct,
    Hosts:          hosts,
    MaxPoolSize:    &maxPoolSize,
    MinPoolSize:    &minPoolSize,
    ReadPreference: readPreference,
    ReplicaSet:     &replicaSet,
  }
)
Copy the code

While the above is correct, it is too bloated and could use a more elegant and concise chain call:

package config

import (
	"time"

	"go.mongodb.org/mongo-driver/mongo/options"
	"go.mongodb.org/mongo-driver/mongo/readpref"
)
// ClientOpts mongoClient connection client parameters
var ClientOpts = options.Client().
  SetAuth(options.Credential{
      AuthMechanism: "SCRAM-SHA-1",
      AuthSource:    "anquan",
      Username:      "ysj",
      Password:      "123456",
  }).
  SetConnectTimeout(10 * time.Second).
  SetHosts([]string{"localhost:27017"}).
  SetMaxPoolSize(20).
  SetMinPoolSize(5).
  SetReadPreference(readpref.Primary()).
  SetReplicaSet("replicaSetDb")
Copy the code

The configuration is then introduced into the main module

package main

import (
  "context"
  "log"
  "mongo-notes/config" // Import the configuration module

  "go.mongodb.org/mongo-driver/mongo"
)

func main(a){
  client, err := mongo.Connect(context.TODO(), config.ClientOpts)
  iferr ! =nil {
    log.Fatal(err)
  }
}
Copy the code

CURD operation

To understand bson

Using mongo-driver to operate mongodb requires the Bson provided by this module. It is mainly used to write the filter of the query, construct the document record and receive the value of the query decoding, that is, to serialize between GO and Mongo. Basically, only the following three data structures are used:

  • bson.D{}: for documentsThe orderlyDescription, key-value separated by commas.
  • bson.M{}: Map structure. Key-values are separated by colons.A disorderly, the most convenient to use;
  • bson.A{}: array structure, element requirement isThe orderlyThat is, the element isbson.D{}Type.

Access to the db

/ / get the db
db := client.Database("test")
collectionNames, err := db.ListCollectionNames(ctx, bson.M{})
fmt.Println("collectionNames:", collectionNames)
Copy the code

Access to the collection

/ / for collecton
collection := db.Collection("person")
fmt.Printf("collection: %s \n", collection.Name())
Copy the code

Create indexes

// Create index
indexView := collection.Indexes()
indexName := "index_by_name"
indexBackground := true
indexUnique := true

indexModel := mongo.IndexModel{
  Keys: bson.D{{"name".1}},
  Options: &options.IndexOptions{
    Name:       &indexName,
    Background: &indexBackground,
    Unique:     &indexUnique,
  },
}
index, err := indexView.CreateOne(ctx, indexModel)
iferr ! =nil {
  log.Fatalf("index created failed. err: %v \n", err)
  return
}
fmt.Println("new index name:", index)
Copy the code

View index

// Check the index
indexCursor, err := collection.Indexes().List(ctx)
var indexes []bson.M
iferr = indexCursor.All(ctx, &indexes); err ! =nil {
  log.Fatal(err)
}
fmt.Println(indexes)
Copy the code

Insert

InsertOne

collection := client.Database("test").Collection("person")
// InsertOne
insertOneResult, err := collection.InsertOne(ctx, bson.M{"name": "Nothing"."gender": "Male"."level": 1})
iferr ! =nil {
  log.Fatal(err)
}
fmt.Println("id:", insertOneResult.InsertedID)
Copy the code

InsertMany

// InsertMany
docs := []interface{}{
  bson.M{"name": "5t5"."gender": "Male"."level": 0},
  bson.M{"name": "Nanemi"."gender": "Male"."level": 1}},// Ordered set to false indicates that one failed insert does not affect the insertion of other documents. The default value is true, and one failed insert will not be written to other documents
insertManyOpts := options.InsertMany().SetOrdered(false)
insertManyResult, err := collection.InsertMany(ctx, docs, insertManyOpts)
iferr ! =nil {
  log.Fatal(err)
}
fmt.Println("ids:", insertManyResult.InsertedIDs)
Copy the code

Find

Find

// Find
findOpts := options.Find().SetSort(bson.D{{"name".1}})
findCursor, err := collection.Find(ctx, bson.M{"level": 0}, findOpts)
var results []bson.M
iferr = findCursor.All(ctx, &results); err ! =nil {
  log.Fatal(err)
}
for _, result := range results {
  fmt.Println(result)
}
Copy the code

FindOne

// FindOne

// Struct can be used to receive decoded results

// var result struct {
// Name string
// Gender string
// Level int
// }

// Or better yet, use bson.m directly
var result bson.M

// Sort by name and skip the first one, and only return the name and level fields
findOneOpts := options.FindOne().SetSkip(1).SetSort(bson.D{{"name".1}}).SetProjection(bson.D{{"name".1}, {"level".1}})

singleResult := collection.FindOne(ctx, bson.M{"name": "5t5"}, findOneOpts)
if err = singleResult.Decode(&result); err == nil {
  fmt.Printf("result: %+v\n", result)
}
Copy the code

FindOneAndDelete

// FindOneAndDelete
findOneAndDeleteOpts := options.FindOneAndDelete().SetProjection(bson.D{{"name".1}, {"level".1}})
var deletedDoc bson.M
singleResult := collection.FindOneAndDelete(ctx, bson.D{{"name"."Nothing"}}, findOneAndDeleteOpts)
iferr = singleResult.Decode(&deletedDoc); err ! =nil {
  if err == mongo.ErrNoDocuments {
      return
  }
  log.Fatal(err)
}
fmt.Printf("deleted document: %+v \n", deletedDoc)
Copy the code

FindOneAndReplace

// FindOneAndReplace
// Note: the document is returned before the replaceMent, and docs that meet the criteria will be completely replaced with replaceMent
_id, err := primitive.ObjectIDFromHex("5fde05b9612cb3d19c4b25e8")
findOneAndReplaceOpts := options.FindOneAndReplace().SetUpsert(true)
replaceMent := bson.M{"name": "5t5"."skill": "Six eye"}
var replaceMentDoc bson.M
err = collection.FindOneAndReplace(ctx, bson.M{"_id": _id}, replaceMent , findOneAndReplaceOpts).Decode(&replaceMentDoc)
iferr ! =nil {
  if err==mongo.ErrNoDocuments {
    return
  }
  log.Fatal(err)
}
fmt.Printf("document before replacement: %v \n", replaceMentDoc)
Copy the code

FindOneAndUpdate

// FindOneAndUpdate
// Note that the result is still the same as the document before the update
_id, err := primitive.ObjectIDFromHex("5fde05b9612cb3d19c4b25e8")
findOneAndUpdateOpts := options.FindOneAndUpdate().SetUpsert(true)
update := bson.M{"$set": bson.M{"level": 0."gender": "Male"}}
var toUpdateDoc bson.M
err = collection.FindOneAndUpdate(ctx, bson.M{"_id": _id}, update, findOneAndUpdateOpts).Decode(&toUpdateDoc)
iferr ! =nil {
  if err == mongo.ErrNoDocuments {
    return
  }
  log.Fatal(err)
}
fmt.Printf("document before updating: %v \n", toUpdateDoc)
}
Copy the code

Update

UpdateOne

//UpdateOne
updateOneOpts := options.Update().SetUpsert(true)
updateOneFilter := bson.M{"name": nanamin}
updateOneSet := bson.M{"$set": bson.M{"skill": "37 cents"}}
updateResult, err := collection.UpdateOne(ctx, updateOneFilter, updateOneSet, updateOneOpts)
fmt.Printf(
  "matched: %d modified: %d upserted: %d upsertedID: %v\n",
  updateResult.MatchedCount,
  updateResult.ModifiedCount,
  updateResult.UpsertedCount,
  updateResult.UpsertedID,
)
Copy the code

UpdateMany

// UpdateMany
updateManyFilter := bson.M{"name": "Nothing"}
updateManySet := bson.M{"$set": bson.M{"level": 1}}
updateManyResult, err := collection.UpdateMany(ctx,updateManyFilter, updateManySet)
fmt.Printf(
  "matched: %d modified: %d upserted: %d upsertedID: %v\n",
  updateManyResult.MatchedCount,
  updateManyResult.ModifiedCount,
  updateManyResult.UpsertedCount,
  updateManyResult.UpsertedID,
)
Copy the code

ReplaceOne

// ReplaceOne
// There is no difference between FindOneAndReplace and FindOneAndReplace on the data level
replaceOpts := options.Replace().SetUpsert(true)
replaceMent := bson.M{"name": "Black"."level": 2."gender": "Male"}
updateResult, err := collection.ReplaceOne(ctx, bson.M{"name": "Nothing"}, replaceMent, replaceOpts)
fmt.Printf(
  "matched: %d modified: %d upserted: %d upsertedID: %v\n",
  updateResult.MatchedCount,
  updateResult.ModifiedCount,
  updateResult.UpsertedCount,
  updateResult.UpsertedID,
)
Copy the code

Delete

DeleteOne

// DeleteOne
deleteOneOpts := options.Delete().SetCollation(&options.Collation{
  // Ignore case
  CaseLevel: false,
})
deleteResult, err := collection.DeleteOne(ctx, bson.D{{"name"."Nothing"}}, deleteOneOpts)
fmt.Println("deletet count:", deleteResult.DeletedCount)
Copy the code

DeleteMany

// DeleteMany
deleteManyOpts := options.Delete().SetCollation(&options.Collation{
  // Ignore case
  CaseLevel: false,
})
deleteManyResult, err := collection.DeleteMany(ctx, bson.D{{"name"."Nothing"}}, deleteOneOpts)
fmt.Println("deletet count:", deleteManyResult.DeletedCount)
Copy the code

Batch operation BulkWrite

// BulkWrite
names := []string{"5t5".nanamin."Black"."Rose"."Nothing"}
models := []mongo.WriteModel{}
updateOperation := bson.M{"$set": bson.M{"Animation": "Spell back to war."}}
for _, name := range names {
  updateOneModel := mongo.NewUpdateOneModel().SetFilter(bson.M{"name": name}).SetUpdate(updateOperation).SetUpsert(true)
  models = append(models, updateOneModel)
}
bulkWriteOpts := options.BulkWrite().SetOrdered(false)
bulkWriteResults, err := collection.BulkWrite(ctx, models, bulkWriteOpts)
iferr ! =nil {
  log.Fatal(err)
}
fmt.Printf(
  "matched: %d modified: %d upserted: %d upsertedIDs: %v\n",
  bulkWriteResults.MatchedCount,
  bulkWriteResults.ModifiedCount,
  bulkWriteResults.UpsertedCount,
  bulkWriteResults.UpsertedIDs,
)
Copy the code

Business transaction

Transactions guarantee that all of our operations will either succeed or fail. The biggest advantage of using transactions is to avoid the impact of a certain operation failure on the existing database environment. I once heard a friend joke that because transactions are not used, after the operation failure, we can only delete data one by one in the production database. So, using transactions is a good habit, even if the code looks bloated.

Mongo-driver transactions need to be started using a session. Any transaction operations need to be in the session context. Here is a comparison of transaction operations using different apis:

Use different apis Active Session Management Active sessionContext management Active transaction abort/commit convenience
mongo.NewSessionContext is is is *
mongo.WithSession is no is 支那
client.UseSessionWithOptions no no is * * *
session.WithTransaction is no no * * * *

mongo.NewSessionContext

package main

import (
  "context"
  "fmt"
  "log"
  "mongo-notes/config"
  "time"

  "go.mongodb.org/mongo-driver/bson"
  "go.mongodb.org/mongo-driver/mongo"
)

func main(a) {
  // ctx
  ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  defer cancel()

  // client
  client, err := mongo.Connect(ctx, config.ClientOpts)
  iferr ! =nil {
    log.Fatal(err)
  }

  // collection
  collection := client.Database("test").Collection("person")

  // session
  session, err := client.StartSession()
  iferr ! =nil {
    panic(err)
  }
  defer session.EndSession(context.TODO())

  // session context
  sessionCtx := mongo.NewSessionContext(ctx, session)

  // session Starts transaction
  iferr = session.StartTransaction(); err ! =nil {
      panic(err)
  }
  // transaction: insertOne in sessionCtx
  insertOneResult, err := collection.InsertOne(sessionCtx, bson.D{{"name"."Big boss"}})
  iferr ! =nil {
    // Use context.background () to ensure abort succeeds, even if mongo's CTX has timed out
    _ = session.AbortTransaction(context.Background())
    panic(err)
  }

  // transaction: findOne in sessionCtx
  var result bson.M
  if err = collection.FindOne(sessionCtx, bson.D{{"_id", insertOneResult.InsertedID}}).Decode(&result); err ! =nil {
    // Use context.background () to ensure abort succeeds, even if mongo's CTX has timed out
    _ = session.AbortTransaction(context.Background())
    panic(err)
  }
  fmt.Printf("result: %v\n", result)

  // Using context.background () ensures that the commit succeeds, even if mongo's CTX has timed out
  iferr = session.CommitTransaction(context.Background()); err ! =nil {
    panic(err)
  }
}

Copy the code

mongo.WithSession

package main

import (
  "context"
  "fmt"
  "log"
  "mongo-notes/config"
  "time"

  "go.mongodb.org/mongo-driver/bson"
  "go.mongodb.org/mongo-driver/mongo"
  "go.mongodb.org/mongo-driver/mongo/options"
  "go.mongodb.org/mongo-driver/mongo/readconcern"
)

func main(a) {
  // ctx
  ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  defer cancel()

  // client
  client, err := mongo.Connect(ctx, config.ClientOpts)
  iferr ! =nil {
      log.Fatal(err)
  }

  // collection
  collection := client.Database("test").Collection("person")

  // session
  sessionOpts := options.Session().SetDefaultReadConcern(readconcern.Majority())
  session, err := client.StartSession(sessionOpts)
  iferr ! =nil {
      log.Fatal(err)
  }
  defer session.EndSession(context.TODO())

  // transaction
  err = mongo.WithSession(ctx, session, func(sessionCtx mongo.SessionContext) error {

    iferr := session.StartTransaction(); err ! =nil {
        return err
    }

    insertOneResult, err := collection.InsertOne(sessionCtx, bson.D{{"name"."Little boss"}})
    iferr ! =nil {
        // Use context.background () to ensure abort succeeds, even if mongo's CTX has timed out
        _ = session.AbortTransaction(context.Background())
        return err
    }

    var result bson.M
    if err = collection.FindOne(sessionCtx, bson.D{{"_id", insertOneResult.InsertedID}}).Decode(&result); err ! =nil {
        // Use context.background () to ensure abort succeeds, even if mongo's CTX has timed out
        _ = session.AbortTransaction(context.Background())
        return err
    }
    fmt.Println(result)

    // Using context.background () ensures that the commit succeeds, even if mongo's CTX has timed out
    return session.CommitTransaction(context.Background())
  })
}
Copy the code

client.UseSessionWithOptions

package main

import (
  "context"
  "fmt"
  "log"
  "mongo-notes/config"
  "time"

  "go.mongodb.org/mongo-driver/bson"
  "go.mongodb.org/mongo-driver/mongo"
  "go.mongodb.org/mongo-driver/mongo/options"
  "go.mongodb.org/mongo-driver/mongo/readconcern"
)

func main(a) {
  // ctx
  ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  defer cancel()

  // client
  client, err := mongo.Connect(ctx, config.ClientOpts)
  iferr ! =nil {
    log.Fatal(err)
  }

  // collection
  collection := client.Database("test").Collection("person")

  // session 
  sessionOpts := options.Session().SetDefaultReadConcern(readconcern.Majority())
  // transaction
  err = client.UseSessionWithOptions(ctx, sessionOpts, func(sessionCtx mongo.SessionContext) error {

    iferr := sessionCtx.StartTransaction(); err ! =nil {
        return err
    }

    insertOneResult, err := collection.InsertOne(sessionCtx, bson.D{{"name"."Scum Five."}})
    iferr ! =nil {
        // Use context.background () to ensure abort succeeds, even if mongo's CTX has timed out
        _ = sessionCtx.AbortTransaction(context.Background())
        return err
    }

    var result bson.M
    if err = collection.FindOne(sessionCtx, bson.D{{"_id", insertOneResult.InsertedID}}).Decode(&result); err ! =nil {
       _ = sessionCtx.AbortTransaction(context.Background())
       return err
    }
    fmt.Println(result)

    // Using context.background () ensures that the commit succeeds, even if mongo's CTX has timed out
    return sessionCtx.CommitTransaction(context.Background())
  })
  iferr ! =nil {
      log.Fatal(err)
  }

}

Copy the code

session.WithTransaction

package main

import (
  "context"
  "fmt"
  "log"
  "mongo-notes/config"
  "time"

  "go.mongodb.org/mongo-driver/bson"
  "go.mongodb.org/mongo-driver/mongo"
  "go.mongodb.org/mongo-driver/mongo/options"
  "go.mongodb.org/mongo-driver/mongo/readconcern"
  "go.mongodb.org/mongo-driver/mongo/readpref"
)

func main(a) {
  // ctx
  ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  defer cancel()

  client, err := mongo.Connect(ctx, config.ClientOpts)
  iferr ! =nil {
    log.Fatal(err)
  }
  // collection
  collection := client.Database("test").Collection("person")

  // session read policy
  sessOpts := options.Session().SetDefaultReadConcern(readconcern.Majority())
  session, err := client.StartSession(sessOpts)
  iferr ! =nil {
    log.Fatal(err)
  }
  defer session.EndSession(context.TODO())

  // Transaction read priority
  transacOpts := options.Transaction().SetReadPreference(readpref.Primary())
  // Insert a record, find a record in the same transaction
  result, err := session.WithTransaction(ctx, func(sessionCtx mongo.SessionContext) (interface{}, error) {
    // insert one
    insertOneResult, err := collection.InsertOne(sessionCtx, bson.M{"name": "Nobody's Part."."level": 5})
    iferr ! =nil {
      log.Fatal(err)
    }
    fmt.Println("inserted id:", insertOneResult.InsertedID)

    // find one
    var result struct {
      Name  string `bson:"name,omitempty"`
      Level int    `bson:"level,omitempty"`
    }
    singleResult := collection.FindOne(sessionCtx, bson.M{"name": "Nobody's Part."})
    iferr = singleResult.Decode(&result); err ! =nil {
      return nil, err
    }

    return result, err

  }, transacOpts)

  iferr ! =nil {
      log.Fatal(err)
  }
  fmt.Printf("find one result: %+v \n", result)
}
Copy the code

Note: this operation will fail if there is no record with the same name in the database. Although a transaction is inserted first, the transaction is a whole and the search is performed before the transaction starts, so the search will fail and the insert will also fail.

Distinct and Count

Distinct

// Distinct
distinctOpts := options.Distinct().SetMaxTime(2 * time.Second)
// Return all the different names
distinctValues, err := collection.Distinct(ctx, "name", bson.M{}, distinctOpts)
iferr ! =nil {
  log.Fatal(err)
}
for _, value := range distinctValues {
  fmt.Println(value)
}
Copy the code

Count

// EstimatedDocumentCount
totalCount, err := collection.EstimatedDocumentCount(ctx)
iferr ! =nil {
  log.Fatal(err)
}
fmt.Println("totalCount:", totalCount)

// CountDocuments
count, err := collection.CountDocuments(ctx, bson.M{"name": "5t5"})
iferr ! =nil {
  log.Fatal(err)
}
fmt.Println("count:", count)
Copy the code

Polymerization of Aggregate

// Aggregate
// Count the number of occurrences by gender
groupStage := bson.D{
  {"$group", bson.D{
    {"_id"."$gender"},
    {"numTimes", bson.D{
      {"$sum".1},
    }},
  }},
}
opts := options.Aggregate().SetMaxTime(2 * time.Second)
aggCursor, err := collection.Aggregate(ctx, mongo.Pipeline{groupStage}, opts)
iferr ! =nil {
  log.Fatal(err)
}

var results []bson.M
iferr = aggCursor.All(ctx, &results); err ! =nil {
  log.Fatal(err)
}
for _, result := range results {
  fmt.Printf("gender %v appears %v times\n", result["_id"], result["numTimes"])}Copy the code

Event Monitoring Watch

The client to monitor

// Monitor all collection inserts in all db
matchStage := bson.D{{"$match", bson.D{{"operationType"."insert"}}}}
opts := options.ChangeStream().SetMaxAwaitTime(2 * time.Second)
changeStream, err := client.Watch(ctx, mongo.Pipeline{matchStage}, opts)
iferr ! =nil {
  log.Fatal(err)
}

for changeStream.Next(ctx) {
  fmt.Println(changeStream.Current)
}

// Insert a document into test.person
{"_id": {"_data": "825FDE28AE000000022B022C0100296E5A10046470407E872C47AFB61ECB12299F90D646645F69640
0645FDE28AE4D0D028CFA4B6B140004"},"operationType": "insert"."clusterTime":
 {"$timestamp": {"t":"1608394926"."i":"2"}},"fullDocument": {"_id": 
{"$oid":"5fde28ae4d0d028cfa4b6b14"},"name": "Rose"."level": 
{"$numberInt":"2"},"gender": "Female"},"ns": {"db": "test"."coll": 
"person"},"documentKey": {"_id": {"$oid":"5fde28ae4d0d028cfa4b6b14"}}}
Copy the code

The database monitor

// db monitors all collection inserts
matchStage := bson.D{{"$match", bson.D{{"operationType"."insert"}}}}
opts := options.ChangeStream().SetMaxAwaitTime(2 * time.Second)
changeStream, err := db.Watch(context.TODO(), mongo.Pipeline{matchStage}, opts)
iferr ! =nil {
  log.Fatal(err)
}

for changeStream.Next(ctx) {
  fmt.Println(changeStream.Current)
}
Copy the code

The collection monitoring

// Only the insertion of the current collection is monitored
matchStage := bson.D{{"$match", bson.D{{"operationType"."insert"}}}}
opts := options.ChangeStream().SetMaxAwaitTime(2 * time.Second)
changeStream, err := collection.Watch(context.TODO(), mongo.Pipeline{matchStage}, opts)
iferr ! =nil {
  log.Fatal(err)
}

for changeStream.Next(ctx) {
  fmt.Println(changeStream.Current)
}
Copy the code

conclusion

In terms of usage, it is true that Python’s Pymongo is more convenient to use.

The resources

  1. Github.com/mongodb/mon…
  2. PKG. Go. Dev/go. Mongo….