...

Source file src/go.mongodb.org/mongo-driver/mongo/crud_examples_test.go

Documentation: go.mongodb.org/mongo-driver/mongo

     1  // Copyright (C) MongoDB, Inc. 2017-present.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"); you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
     6  
     7  package mongo_test
     8  
     9  import (
    10  	"context"
    11  	"errors"
    12  	"fmt"
    13  	"log"
    14  	"sync"
    15  	"time"
    16  
    17  	"go.mongodb.org/mongo-driver/bson"
    18  	"go.mongodb.org/mongo-driver/bson/primitive"
    19  	"go.mongodb.org/mongo-driver/mongo"
    20  	"go.mongodb.org/mongo-driver/mongo/options"
    21  	"go.mongodb.org/mongo-driver/mongo/readconcern"
    22  	"go.mongodb.org/mongo-driver/mongo/readpref"
    23  )
    24  
    25  // Client examples
    26  
    27  func ExampleClient_ListDatabaseNames() {
    28  	var client *mongo.Client
    29  
    30  	// Use a filter to only select non-empty databases.
    31  	result, err := client.ListDatabaseNames(
    32  		context.TODO(),
    33  		bson.D{{"empty", false}})
    34  	if err != nil {
    35  		log.Fatal(err)
    36  	}
    37  
    38  	for _, db := range result {
    39  		fmt.Println(db)
    40  	}
    41  }
    42  
    43  func ExampleClient_Watch() {
    44  	var client *mongo.Client
    45  
    46  	// Specify a pipeline that will only match "insert" events.
    47  	// Specify the MaxAwaitTimeOption to have each attempt wait two seconds for
    48  	// new documents.
    49  	matchStage := bson.D{{"$match", bson.D{{"operationType", "insert"}}}}
    50  	opts := options.ChangeStream().SetMaxAwaitTime(2 * time.Second)
    51  	changeStream, err := client.Watch(
    52  		context.TODO(),
    53  		mongo.Pipeline{matchStage},
    54  		opts)
    55  	if err != nil {
    56  		log.Fatal(err)
    57  	}
    58  
    59  	// Print out all change stream events in the order they're received.
    60  	// See the mongo.ChangeStream documentation for more examples of using
    61  	// change streams.
    62  	for changeStream.Next(context.TODO()) {
    63  		fmt.Println(changeStream.Current)
    64  	}
    65  }
    66  
    67  // Database examples
    68  
    69  func ExampleDatabase_CreateCollection() {
    70  	var db *mongo.Database
    71  
    72  	// Create a "users" collection with a JSON schema validator. The validator
    73  	// will ensure that each document in the collection has "name" and "age"
    74  	// fields.
    75  	jsonSchema := bson.M{
    76  		"bsonType": "object",
    77  		"required": []string{"name", "age"},
    78  		"properties": bson.M{
    79  			"name": bson.M{
    80  				"bsonType": "string",
    81  				"description": "the name of the user, which is required and " +
    82  					"must be a string",
    83  			},
    84  			"age": bson.M{
    85  				"bsonType": "int",
    86  				"minimum":  18,
    87  				"description": "the age of the user, which is required and " +
    88  					"must be an integer >= 18",
    89  			},
    90  		},
    91  	}
    92  	validator := bson.M{
    93  		"$jsonSchema": jsonSchema,
    94  	}
    95  	opts := options.CreateCollection().SetValidator(validator)
    96  
    97  	err := db.CreateCollection(context.TODO(), "users", opts)
    98  	if err != nil {
    99  		log.Fatal(err)
   100  	}
   101  }
   102  
   103  func ExampleDatabase_CreateView() {
   104  	var db *mongo.Database
   105  
   106  	// Create a view on the "users" collection called "usernames". Specify a
   107  	// pipeline that concatenates the "firstName" and "lastName" fields from
   108  	// each document in "users" and projects the result into the "fullName"
   109  	// field in the view.
   110  	projectStage := bson.D{
   111  		{"$project", bson.D{
   112  			{"_id", 0},
   113  			{"fullName", bson.D{
   114  				{"$concat", []string{"$firstName", " ", "$lastName"}},
   115  			}},
   116  		}},
   117  	}
   118  	pipeline := mongo.Pipeline{projectStage}
   119  
   120  	// Specify the Collation option to set a default collation for the view.
   121  	opts := options.CreateView().SetCollation(&options.Collation{
   122  		Locale: "en_US",
   123  	})
   124  
   125  	err := db.CreateView(context.TODO(), "usernames", "users", pipeline, opts)
   126  	if err != nil {
   127  		log.Fatal(err)
   128  	}
   129  }
   130  
   131  func ExampleDatabase_ListCollectionNames() {
   132  	var db *mongo.Database
   133  
   134  	// Use a filter to only select capped collections.
   135  	result, err := db.ListCollectionNames(
   136  		context.TODO(),
   137  		bson.D{{"options.capped", true}})
   138  	if err != nil {
   139  		log.Fatal(err)
   140  	}
   141  
   142  	for _, coll := range result {
   143  		fmt.Println(coll)
   144  	}
   145  }
   146  
   147  func ExampleDatabase_RunCommand() {
   148  	var db *mongo.Database
   149  
   150  	// Run an explain command to see the query plan for when a "find" is
   151  	// executed on collection "bar" specify the ReadPreference option to
   152  	// explicitly set the read preference to primary.
   153  	findCmd := bson.D{{"find", "bar"}}
   154  	command := bson.D{{"explain", findCmd}}
   155  	opts := options.RunCmd().SetReadPreference(readpref.Primary())
   156  	var result bson.M
   157  	err := db.RunCommand(context.TODO(), command, opts).Decode(&result)
   158  	if err != nil {
   159  		log.Fatal(err)
   160  	}
   161  	fmt.Println(result)
   162  }
   163  
   164  func ExampleDatabase_Watch() {
   165  	var db *mongo.Database
   166  
   167  	// Specify a pipeline that will only match "insert" events.
   168  	// Specify the MaxAwaitTimeOption to have each attempt wait two seconds for
   169  	// new documents.
   170  	matchStage := bson.D{{"$match", bson.D{{"operationType", "insert"}}}}
   171  	opts := options.ChangeStream().SetMaxAwaitTime(2 * time.Second)
   172  	changeStream, err := db.Watch(
   173  		context.TODO(),
   174  		mongo.Pipeline{matchStage},
   175  		opts)
   176  	if err != nil {
   177  		log.Fatal(err)
   178  	}
   179  
   180  	// Print out all change stream events in the order they're received.
   181  	// See the mongo.ChangeStream documentation for more examples of using
   182  	// change streams
   183  	for changeStream.Next(context.TODO()) {
   184  		fmt.Println(changeStream.Current)
   185  	}
   186  }
   187  
   188  // Collection examples
   189  
   190  func ExampleCollection_Aggregate() {
   191  	var coll *mongo.Collection
   192  
   193  	// Specify a pipeline that will return the number of times each name appears
   194  	// in the collection.
   195  	// Specify the MaxTime option to limit the amount of time the operation can
   196  	// run on the server.
   197  	groupStage := bson.D{
   198  		{"$group", bson.D{
   199  			{"_id", "$name"},
   200  			{"numTimes", bson.D{
   201  				{"$sum", 1},
   202  			}},
   203  		}},
   204  	}
   205  	opts := options.Aggregate().SetMaxTime(2 * time.Second)
   206  	cursor, err := coll.Aggregate(
   207  		context.TODO(),
   208  		mongo.Pipeline{groupStage},
   209  		opts)
   210  	if err != nil {
   211  		log.Fatal(err)
   212  	}
   213  
   214  	// Get a list of all returned documents and print them out.
   215  	// See the mongo.Cursor documentation for more examples of using cursors.
   216  	var results []bson.M
   217  	if err = cursor.All(context.TODO(), &results); err != nil {
   218  		log.Fatal(err)
   219  	}
   220  	for _, result := range results {
   221  		fmt.Printf(
   222  			"name %v appears %v times\n",
   223  			result["_id"],
   224  			result["numTimes"])
   225  	}
   226  }
   227  
   228  func ExampleCollection_BulkWrite() {
   229  	var coll *mongo.Collection
   230  	var firstID, secondID primitive.ObjectID
   231  
   232  	// Update the "email" field for two users.
   233  	// For each update, specify the Upsert option to insert a new document if a
   234  	// document matching the filter isn't found.
   235  	// Set the Ordered option to false to allow both operations to happen even
   236  	// if one of them errors.
   237  	firstUpdate := bson.D{
   238  		{"$set", bson.D{
   239  			{"email", "firstEmail@example.com"},
   240  		}},
   241  	}
   242  	secondUpdate := bson.D{
   243  		{"$set", bson.D{
   244  			{"email", "secondEmail@example.com"},
   245  		}},
   246  	}
   247  	models := []mongo.WriteModel{
   248  		mongo.NewUpdateOneModel().SetFilter(bson.D{{"_id", firstID}}).
   249  			SetUpdate(firstUpdate).SetUpsert(true),
   250  		mongo.NewUpdateOneModel().SetFilter(bson.D{{"_id", secondID}}).
   251  			SetUpdate(secondUpdate).SetUpsert(true),
   252  	}
   253  	opts := options.BulkWrite().SetOrdered(false)
   254  	res, err := coll.BulkWrite(context.TODO(), models, opts)
   255  	if err != nil {
   256  		log.Fatal(err)
   257  	}
   258  
   259  	fmt.Printf(
   260  		"inserted %v and deleted %v documents\n",
   261  		res.InsertedCount,
   262  		res.DeletedCount)
   263  }
   264  
   265  func ExampleCollection_CountDocuments() {
   266  	var coll *mongo.Collection
   267  
   268  	// Count the number of times the name "Bob" appears in the collection.
   269  	// Specify the MaxTime option to limit the amount of time the operation can
   270  	// run on the server.
   271  	opts := options.Count().SetMaxTime(2 * time.Second)
   272  	count, err := coll.CountDocuments(
   273  		context.TODO(),
   274  		bson.D{{"name", "Bob"}},
   275  		opts)
   276  	if err != nil {
   277  		log.Fatal(err)
   278  	}
   279  	fmt.Printf("name Bob appears in %v documents", count)
   280  }
   281  
   282  func ExampleCollection_DeleteMany() {
   283  	var coll *mongo.Collection
   284  
   285  	// Delete all documents in which the "name" field is "Bob" or "bob".
   286  	// Specify the Collation option to provide a collation that will ignore case
   287  	// for string comparisons.
   288  	opts := options.Delete().SetCollation(&options.Collation{
   289  		Locale:    "en_US",
   290  		Strength:  1,
   291  		CaseLevel: false,
   292  	})
   293  	res, err := coll.DeleteMany(context.TODO(), bson.D{{"name", "bob"}}, opts)
   294  	if err != nil {
   295  		log.Fatal(err)
   296  	}
   297  	fmt.Printf("deleted %v documents\n", res.DeletedCount)
   298  }
   299  
   300  func ExampleCollection_DeleteOne() {
   301  	var coll *mongo.Collection
   302  
   303  	// Delete at most one document in which the "name" field is "Bob" or "bob".
   304  	// Specify the SetCollation option to provide a collation that will ignore
   305  	// case for string comparisons.
   306  	opts := options.Delete().SetCollation(&options.Collation{
   307  		Locale:    "en_US",
   308  		Strength:  1,
   309  		CaseLevel: false,
   310  	})
   311  	res, err := coll.DeleteOne(context.TODO(), bson.D{{"name", "bob"}}, opts)
   312  	if err != nil {
   313  		log.Fatal(err)
   314  	}
   315  	fmt.Printf("deleted %v documents\n", res.DeletedCount)
   316  }
   317  
   318  func ExampleCollection_Distinct() {
   319  	var coll *mongo.Collection
   320  
   321  	// Find all unique values for the "name" field for documents in which the
   322  	// "age" field is greater than 25.
   323  	// Specify the MaxTime option to limit the amount of time the operation can
   324  	// run on the server.
   325  	filter := bson.D{{"age", bson.D{{"$gt", 25}}}}
   326  	opts := options.Distinct().SetMaxTime(2 * time.Second)
   327  	values, err := coll.Distinct(context.TODO(), "name", filter, opts)
   328  	if err != nil {
   329  		log.Fatal(err)
   330  	}
   331  
   332  	for _, value := range values {
   333  		fmt.Println(value)
   334  	}
   335  }
   336  
   337  func ExampleCollection_EstimatedDocumentCount() {
   338  	var coll *mongo.Collection
   339  
   340  	// Get and print an estimated of the number of documents in the collection.
   341  	// Specify the MaxTime option to limit the amount of time the operation can
   342  	// run on the server.
   343  	opts := options.EstimatedDocumentCount().SetMaxTime(2 * time.Second)
   344  	count, err := coll.EstimatedDocumentCount(context.TODO(), opts)
   345  	if err != nil {
   346  		log.Fatal(err)
   347  	}
   348  	fmt.Printf("estimated document count: %v", count)
   349  }
   350  
   351  func ExampleCollection_Find() {
   352  	var coll *mongo.Collection
   353  
   354  	// Find all documents in which the "name" field is "Bob".
   355  	// Specify the Sort option to sort the returned documents by age in
   356  	// ascending order.
   357  	opts := options.Find().SetSort(bson.D{{"age", 1}})
   358  	cursor, err := coll.Find(context.TODO(), bson.D{{"name", "Bob"}}, opts)
   359  	if err != nil {
   360  		log.Fatal(err)
   361  	}
   362  
   363  	// Get a list of all returned documents and print them out.
   364  	// See the mongo.Cursor documentation for more examples of using cursors.
   365  	var results []bson.M
   366  	if err = cursor.All(context.TODO(), &results); err != nil {
   367  		log.Fatal(err)
   368  	}
   369  	for _, result := range results {
   370  		fmt.Println(result)
   371  	}
   372  }
   373  
   374  func ExampleCollection_FindOne() {
   375  	var coll *mongo.Collection
   376  	var id primitive.ObjectID
   377  
   378  	// Find the document for which the _id field matches id.
   379  	// Specify the Sort option to sort the documents by age.
   380  	// The first document in the sorted order will be returned.
   381  	opts := options.FindOne().SetSort(bson.D{{"age", 1}})
   382  	var result bson.M
   383  	err := coll.FindOne(
   384  		context.TODO(),
   385  		bson.D{{"_id", id}},
   386  		opts,
   387  	).Decode(&result)
   388  	if err != nil {
   389  		// ErrNoDocuments means that the filter did not match any documents in
   390  		// the collection.
   391  		if errors.Is(err, mongo.ErrNoDocuments) {
   392  			return
   393  		}
   394  		log.Fatal(err)
   395  	}
   396  	fmt.Printf("found document %v", result)
   397  }
   398  
   399  func ExampleCollection_FindOneAndDelete() {
   400  	var coll *mongo.Collection
   401  	var id primitive.ObjectID
   402  
   403  	// Find and delete the document for which the _id field matches id.
   404  	// Specify the Projection option to only include the name and age fields in
   405  	// the returned document.
   406  	opts := options.FindOneAndDelete().
   407  		SetProjection(bson.D{{"name", 1}, {"age", 1}})
   408  	var deletedDocument bson.M
   409  	err := coll.FindOneAndDelete(
   410  		context.TODO(),
   411  		bson.D{{"_id", id}},
   412  		opts,
   413  	).Decode(&deletedDocument)
   414  	if err != nil {
   415  		// ErrNoDocuments means that the filter did not match any documents in
   416  		// the collection.
   417  		if errors.Is(err, mongo.ErrNoDocuments) {
   418  			return
   419  		}
   420  		log.Fatal(err)
   421  	}
   422  	fmt.Printf("deleted document %v", deletedDocument)
   423  }
   424  
   425  func ExampleCollection_FindOneAndReplace() {
   426  	var coll *mongo.Collection
   427  	var id primitive.ObjectID
   428  
   429  	// Find the document for which the _id field matches id and add a field
   430  	// called "location".
   431  	// Specify the Upsert option to insert a new document if a document matching
   432  	// the filter isn't found.
   433  	opts := options.FindOneAndReplace().SetUpsert(true)
   434  	filter := bson.D{{"_id", id}}
   435  	replacement := bson.D{{"location", "NYC"}}
   436  	var replacedDocument bson.M
   437  	err := coll.FindOneAndReplace(
   438  		context.TODO(),
   439  		filter,
   440  		replacement,
   441  		opts,
   442  	).Decode(&replacedDocument)
   443  	if err != nil {
   444  		// ErrNoDocuments means that the filter did not match any documents in
   445  		// the collection.
   446  		if errors.Is(err, mongo.ErrNoDocuments) {
   447  			return
   448  		}
   449  		log.Fatal(err)
   450  	}
   451  	fmt.Printf("replaced document %v", replacedDocument)
   452  }
   453  
   454  func ExampleCollection_FindOneAndUpdate() {
   455  	var coll *mongo.Collection
   456  	var id primitive.ObjectID
   457  
   458  	// Find the document for which the _id field matches id and set the email to
   459  	// "newemail@example.com".
   460  	// Specify the Upsert option to insert a new document if a document matching
   461  	// the filter isn't found.
   462  	opts := options.FindOneAndUpdate().SetUpsert(true)
   463  	filter := bson.D{{"_id", id}}
   464  	update := bson.D{{"$set", bson.D{{"email", "newemail@example.com"}}}}
   465  	var updatedDocument bson.M
   466  	err := coll.FindOneAndUpdate(
   467  		context.TODO(),
   468  		filter,
   469  		update,
   470  		opts,
   471  	).Decode(&updatedDocument)
   472  	if err != nil {
   473  		// ErrNoDocuments means that the filter did not match any documents in
   474  		// the collection.
   475  		if errors.Is(err, mongo.ErrNoDocuments) {
   476  			return
   477  		}
   478  		log.Fatal(err)
   479  	}
   480  	fmt.Printf("updated document %v", updatedDocument)
   481  }
   482  
   483  func ExampleCollection_InsertMany() {
   484  	var coll *mongo.Collection
   485  
   486  	// Insert documents {name: "Alice"} and {name: "Bob"}.
   487  	// Set the Ordered option to false to allow both operations to happen even
   488  	// if one of them errors.
   489  	docs := []interface{}{
   490  		bson.D{{"name", "Alice"}},
   491  		bson.D{{"name", "Bob"}},
   492  	}
   493  	opts := options.InsertMany().SetOrdered(false)
   494  	res, err := coll.InsertMany(context.TODO(), docs, opts)
   495  	if err != nil {
   496  		log.Fatal(err)
   497  	}
   498  	fmt.Printf("inserted documents with IDs %v\n", res.InsertedIDs)
   499  }
   500  
   501  func ExampleCollection_InsertOne() {
   502  	var coll *mongo.Collection
   503  
   504  	// Insert the document {name: "Alice"}.
   505  	res, err := coll.InsertOne(context.TODO(), bson.D{{"name", "Alice"}})
   506  	if err != nil {
   507  		log.Fatal(err)
   508  	}
   509  	fmt.Printf("inserted document with ID %v\n", res.InsertedID)
   510  }
   511  
   512  func ExampleCollection_ReplaceOne() {
   513  	var coll *mongo.Collection
   514  	var id primitive.ObjectID
   515  
   516  	// Find the document for which the _id field matches id and add a field
   517  	// called "location".
   518  	// Specify the Upsert option to insert a new document if a document matching
   519  	// the filter isn't found.
   520  	opts := options.Replace().SetUpsert(true)
   521  	filter := bson.D{{"_id", id}}
   522  	replacement := bson.D{{"location", "NYC"}}
   523  	result, err := coll.ReplaceOne(context.TODO(), filter, replacement, opts)
   524  	if err != nil {
   525  		log.Fatal(err)
   526  	}
   527  
   528  	if result.MatchedCount != 0 {
   529  		fmt.Println("matched and replaced an existing document")
   530  		return
   531  	}
   532  	if result.UpsertedCount != 0 {
   533  		fmt.Printf("inserted a new document with ID %v\n", result.UpsertedID)
   534  	}
   535  }
   536  
   537  func ExampleCollection_UpdateMany() {
   538  	var coll *mongo.Collection
   539  
   540  	// Increment the age for all users whose birthday is today.
   541  	today := time.Now().Format("01-01-1970")
   542  	filter := bson.D{{"birthday", today}}
   543  	update := bson.D{{"$inc", bson.D{{"age", 1}}}}
   544  
   545  	result, err := coll.UpdateMany(context.TODO(), filter, update)
   546  	if err != nil {
   547  		log.Fatal(err)
   548  	}
   549  
   550  	if result.MatchedCount != 0 {
   551  		fmt.Println("matched and replaced an existing document")
   552  		return
   553  	}
   554  }
   555  
   556  func ExampleCollection_UpdateOne() {
   557  	var coll *mongo.Collection
   558  	var id primitive.ObjectID
   559  
   560  	// Find the document for which the _id field matches id and set the email to
   561  	// "newemail@example.com".
   562  	// Specify the Upsert option to insert a new document if a document matching
   563  	// the filter isn't found.
   564  	opts := options.Update().SetUpsert(true)
   565  	filter := bson.D{{"_id", id}}
   566  	update := bson.D{{"$set", bson.D{{"email", "newemail@example.com"}}}}
   567  
   568  	result, err := coll.UpdateOne(context.TODO(), filter, update, opts)
   569  	if err != nil {
   570  		log.Fatal(err)
   571  	}
   572  
   573  	if result.MatchedCount != 0 {
   574  		fmt.Println("matched and replaced an existing document")
   575  		return
   576  	}
   577  	if result.UpsertedCount != 0 {
   578  		fmt.Printf("inserted a new document with ID %v\n", result.UpsertedID)
   579  	}
   580  }
   581  
   582  func ExampleCollection_Watch() {
   583  	var collection *mongo.Collection
   584  
   585  	// Specify a pipeline that will only match "insert" events.
   586  	// Specify the MaxAwaitTimeOption to have each attempt wait two seconds for
   587  	// new documents.
   588  	matchStage := bson.D{{"$match", bson.D{{"operationType", "insert"}}}}
   589  	opts := options.ChangeStream().SetMaxAwaitTime(2 * time.Second)
   590  	changeStream, err := collection.Watch(
   591  		context.TODO(),
   592  		mongo.Pipeline{matchStage},
   593  		opts)
   594  	if err != nil {
   595  		log.Fatal(err)
   596  	}
   597  
   598  	// Print out all change stream events in the order they're received.
   599  	// See the mongo.ChangeStream documentation for more examples of using
   600  	// change streams.
   601  	for changeStream.Next(context.TODO()) {
   602  		fmt.Println(changeStream.Current)
   603  	}
   604  }
   605  
   606  // Session examples
   607  
   608  func ExampleWithSession() {
   609  	// Assume client is configured with write concern majority and read
   610  	// preference primary.
   611  	var client *mongo.Client
   612  
   613  	// Specify the DefaultReadConcern option so any transactions started through
   614  	// the session will have read concern majority.
   615  	// The DefaultReadPreference and DefaultWriteConcern options aren't
   616  	// specified so they will be inheritied from client and be set to primary
   617  	// and majority, respectively.
   618  	opts := options.Session().SetDefaultReadConcern(readconcern.Majority())
   619  	sess, err := client.StartSession(opts)
   620  	if err != nil {
   621  		log.Fatal(err)
   622  	}
   623  	defer sess.EndSession(context.TODO())
   624  
   625  	// Call WithSession to start a transaction within the new session.
   626  	err = mongo.WithSession(
   627  		context.TODO(),
   628  		sess,
   629  		func(ctx mongo.SessionContext) error {
   630  			// Use the mongo.SessionContext as the Context parameter for
   631  			// InsertOne and FindOne so both operations are run under the new
   632  			// Session.
   633  
   634  			if err := sess.StartTransaction(); err != nil {
   635  				return err
   636  			}
   637  
   638  			coll := client.Database("db").Collection("coll")
   639  			res, err := coll.InsertOne(ctx, bson.D{{"x", 1}})
   640  			if err != nil {
   641  				// Abort the transaction after an error. Use
   642  				// context.Background() to ensure that the abort can complete
   643  				// successfully even if the context passed to mongo.WithSession
   644  				// is changed to have a timeout.
   645  				_ = sess.AbortTransaction(context.Background())
   646  				return err
   647  			}
   648  
   649  			var result bson.M
   650  			err = coll.FindOne(
   651  				ctx,
   652  				bson.D{{"_id", res.InsertedID}},
   653  			).Decode(result)
   654  			if err != nil {
   655  				// Abort the transaction after an error. Use
   656  				// context.Background() to ensure that the abort can complete
   657  				// successfully even if the context passed to mongo.WithSession
   658  				// is changed to have a timeout.
   659  				_ = sess.AbortTransaction(context.Background())
   660  				return err
   661  			}
   662  			fmt.Println(result)
   663  
   664  			// Use context.Background() to ensure that the commit can complete
   665  			// successfully even if the context passed to mongo.WithSession is
   666  			// changed to have a timeout.
   667  			return sess.CommitTransaction(context.Background())
   668  		})
   669  	if err != nil {
   670  		log.Fatal(err)
   671  	}
   672  }
   673  
   674  func ExampleClient_UseSessionWithOptions() {
   675  	var client *mongo.Client
   676  
   677  	// Specify the DefaultReadConcern option so any transactions started through
   678  	// the session will have read concern majority.
   679  	// The DefaultReadPreference and DefaultWriteConcern options aren't
   680  	// specified so they will be inheritied from client and be set to primary
   681  	// and majority, respectively.
   682  	opts := options.Session().SetDefaultReadConcern(readconcern.Majority())
   683  	err := client.UseSessionWithOptions(
   684  		context.TODO(),
   685  		opts,
   686  		func(ctx mongo.SessionContext) error {
   687  			// Use the mongo.SessionContext as the Context parameter for
   688  			// InsertOne and FindOne so both operations are run under the new
   689  			// Session.
   690  
   691  			if err := ctx.StartTransaction(); err != nil {
   692  				return err
   693  			}
   694  
   695  			coll := client.Database("db").Collection("coll")
   696  			res, err := coll.InsertOne(ctx, bson.D{{"x", 1}})
   697  			if err != nil {
   698  				// Abort the transaction after an error. Use
   699  				// context.Background() to ensure that the abort can complete
   700  				// successfully even if the context passed to mongo.WithSession
   701  				// is changed to have a timeout.
   702  				_ = ctx.AbortTransaction(context.Background())
   703  				return err
   704  			}
   705  
   706  			var result bson.M
   707  			err = coll.FindOne(
   708  				ctx,
   709  				bson.D{{"_id", res.InsertedID}},
   710  			).Decode(result)
   711  			if err != nil {
   712  				// Abort the transaction after an error. Use
   713  				// context.Background() to ensure that the abort can complete
   714  				// successfully even if the context passed to mongo.WithSession
   715  				// is changed to have a timeout.
   716  				_ = ctx.AbortTransaction(context.Background())
   717  				return err
   718  			}
   719  			fmt.Println(result)
   720  
   721  			// Use context.Background() to ensure that the commit can complete
   722  			// successfully even if the context passed to mongo.WithSession is
   723  			// changed to have a timeout.
   724  			return ctx.CommitTransaction(context.Background())
   725  		})
   726  	if err != nil {
   727  		log.Fatal(err)
   728  	}
   729  }
   730  
   731  func ExampleClient_StartSession_withTransaction() {
   732  	// Assume client is configured with write concern majority and read
   733  	// preference primary.
   734  	var client *mongo.Client
   735  
   736  	// Specify the DefaultReadConcern option so any transactions started through
   737  	// the session will have read concern majority.
   738  	// The DefaultReadPreference and DefaultWriteConcern options aren't
   739  	// specified so they will be inheritied from client and be set to primary
   740  	// and majority, respectively.
   741  	opts := options.Session().SetDefaultReadConcern(readconcern.Majority())
   742  	sess, err := client.StartSession(opts)
   743  	if err != nil {
   744  		log.Fatal(err)
   745  	}
   746  	defer sess.EndSession(context.TODO())
   747  
   748  	// Specify the ReadPreference option to set the read preference to primary
   749  	// preferred for this transaction.
   750  	txnOpts := options.Transaction().
   751  		SetReadPreference(readpref.PrimaryPreferred())
   752  	result, err := sess.WithTransaction(
   753  		context.TODO(),
   754  		func(ctx mongo.SessionContext) (interface{}, error) {
   755  			// Use the mongo.SessionContext as the Context parameter for
   756  			// InsertOne and FindOne so both operations are run in the same
   757  			// transaction.
   758  
   759  			coll := client.Database("db").Collection("coll")
   760  			res, err := coll.InsertOne(ctx, bson.D{{"x", 1}})
   761  			if err != nil {
   762  				return nil, err
   763  			}
   764  
   765  			var result bson.M
   766  			err = coll.FindOne(
   767  				ctx,
   768  				bson.D{{"_id", res.InsertedID}},
   769  			).Decode(result)
   770  			if err != nil {
   771  				return nil, err
   772  			}
   773  			return result, err
   774  		},
   775  		txnOpts)
   776  	if err != nil {
   777  		log.Fatal(err)
   778  	}
   779  	fmt.Printf("result: %v\n", result)
   780  }
   781  
   782  func ExampleNewSessionContext() {
   783  	var client *mongo.Client
   784  
   785  	// Create a new Session and SessionContext.
   786  	sess, err := client.StartSession()
   787  	if err != nil {
   788  		panic(err)
   789  	}
   790  	defer sess.EndSession(context.TODO())
   791  	ctx := mongo.NewSessionContext(context.TODO(), sess)
   792  
   793  	// Start a transaction and use the mongo.SessionContext as the Context
   794  	// parameter for InsertOne and FindOne so both operations are run in the
   795  	// transaction.
   796  	if err = sess.StartTransaction(); err != nil {
   797  		panic(err)
   798  	}
   799  
   800  	coll := client.Database("db").Collection("coll")
   801  	res, err := coll.InsertOne(ctx, bson.D{{"x", 1}})
   802  	if err != nil {
   803  		// Abort the transaction after an error. Use context.Background() to
   804  		// ensure that the abort can complete successfully even if the context
   805  		// passed to NewSessionContext is changed to have a timeout.
   806  		_ = sess.AbortTransaction(context.Background())
   807  		panic(err)
   808  	}
   809  
   810  	var result bson.M
   811  	err = coll.FindOne(
   812  		ctx,
   813  		bson.D{{"_id", res.InsertedID}},
   814  	).Decode(&result)
   815  	if err != nil {
   816  		// Abort the transaction after an error. Use context.Background() to
   817  		// ensure that the abort can complete successfully even if the context
   818  		// passed to NewSessionContext is changed to have a timeout.
   819  		_ = sess.AbortTransaction(context.Background())
   820  		panic(err)
   821  	}
   822  	fmt.Printf("result: %v\n", result)
   823  
   824  	// Commit the transaction so the inserted document will be stored. Use
   825  	// context.Background() to ensure that the commit can complete successfully
   826  	// even if the context passed to NewSessionContext is changed to have a
   827  	// timeout.
   828  	if err = sess.CommitTransaction(context.Background()); err != nil {
   829  		panic(err)
   830  	}
   831  }
   832  
   833  // Cursor examples
   834  
   835  func ExampleCursor_All() {
   836  	var cursor *mongo.Cursor
   837  
   838  	var results []bson.M
   839  	if err := cursor.All(context.TODO(), &results); err != nil {
   840  		log.Fatal(err)
   841  	}
   842  	fmt.Println(results)
   843  }
   844  
   845  func ExampleCursor_Next() {
   846  	var cursor *mongo.Cursor
   847  	defer cursor.Close(context.TODO())
   848  
   849  	// Iterate the cursor and print out each document until the cursor is
   850  	// exhausted or there is an error getting the next document.
   851  	for cursor.Next(context.TODO()) {
   852  		// A new result variable should be declared for each document.
   853  		var result bson.M
   854  		if err := cursor.Decode(&result); err != nil {
   855  			log.Fatal(err)
   856  		}
   857  		fmt.Println(result)
   858  	}
   859  	if err := cursor.Err(); err != nil {
   860  		log.Fatal(err)
   861  	}
   862  }
   863  
   864  func ExampleCursor_TryNext() {
   865  	var cursor *mongo.Cursor
   866  	defer cursor.Close(context.TODO())
   867  
   868  	// Iterate the cursor and print out each document until the cursor is
   869  	// exhausted or there is an error getting the next document.
   870  	for {
   871  		if cursor.TryNext(context.TODO()) {
   872  			// A new result variable should be declared for each document.
   873  			var result bson.M
   874  			if err := cursor.Decode(&result); err != nil {
   875  				log.Fatal(err)
   876  			}
   877  			fmt.Println(result)
   878  			continue
   879  		}
   880  
   881  		// If TryNext returns false, the next document is not yet available, the
   882  		// cursor was exhausted and was closed, or an error occurred. TryNext
   883  		// should only be called again for the empty batch case.
   884  		if err := cursor.Err(); err != nil {
   885  			log.Fatal(err)
   886  		}
   887  		if cursor.ID() == 0 {
   888  			break
   889  		}
   890  	}
   891  }
   892  
   893  func ExampleCursor_RemainingBatchLength() {
   894  	// Because we're using a tailable cursor, this must be a handle to a capped
   895  	// collection.
   896  	var coll *mongo.Collection
   897  
   898  	// Create a tailable await cursor. Specify the MaxAwaitTime option so
   899  	// requests to get more data will return if there are no documents available
   900  	// after two seconds.
   901  	findOpts := options.Find().
   902  		SetCursorType(options.TailableAwait).
   903  		SetMaxAwaitTime(2 * time.Second)
   904  	cursor, err := coll.Find(context.TODO(), bson.D{}, findOpts)
   905  	if err != nil {
   906  		panic(err)
   907  	}
   908  
   909  	for {
   910  		// Iterate the cursor using TryNext.
   911  		if cursor.TryNext(context.TODO()) {
   912  			fmt.Println(cursor.Current)
   913  		}
   914  
   915  		// Handle cursor errors or the cursor being closed by the server.
   916  		if err = cursor.Err(); err != nil {
   917  			panic(err)
   918  		}
   919  		if cursor.ID() == 0 {
   920  			panic("cursor was unexpectedly closed by the server")
   921  		}
   922  
   923  		// Use the RemainingBatchLength function to rate-limit the number of
   924  		// network requests the driver does. If the current batch is empty,
   925  		// sleep for a short amount of time to let documents build up on the
   926  		// server before the next TryNext call, which will do a network request.
   927  		if cursor.RemainingBatchLength() == 0 {
   928  			time.Sleep(100 * time.Millisecond)
   929  		}
   930  	}
   931  }
   932  
   933  // ChangeStream examples
   934  
   935  func ExampleChangeStream_Next() {
   936  	var stream *mongo.ChangeStream
   937  	defer stream.Close(context.TODO())
   938  
   939  	// Iterate the change stream and print out each event.
   940  	// Because the Next call blocks until an event is available, another way to
   941  	// iterate the change stream is to call Next in a goroutine and pass in a
   942  	// context that can be cancelled to abort the call.
   943  
   944  	for stream.Next(context.TODO()) {
   945  		// A new event variable should be declared for each event.
   946  		var event bson.M
   947  		if err := stream.Decode(&event); err != nil {
   948  			log.Fatal(err)
   949  		}
   950  		fmt.Println(event)
   951  	}
   952  	if err := stream.Err(); err != nil {
   953  		log.Fatal(err)
   954  	}
   955  }
   956  
   957  func ExampleChangeStream_TryNext() {
   958  	var stream *mongo.ChangeStream
   959  	defer stream.Close(context.TODO())
   960  
   961  	// Iterate the change stream and print out each event until the change
   962  	// stream is closed by the server or there is an error getting the next
   963  	// event.
   964  	for {
   965  		if stream.TryNext(context.TODO()) {
   966  			// A new event variable should be declared for each event.
   967  			var event bson.M
   968  			if err := stream.Decode(&event); err != nil {
   969  				log.Fatal(err)
   970  			}
   971  			fmt.Println(event)
   972  			continue
   973  		}
   974  
   975  		// If TryNext returns false, the next change is not yet available, the
   976  		// change stream was closed by the server, or an error occurred. TryNext
   977  		// should only be called again for the empty batch case.
   978  		if err := stream.Err(); err != nil {
   979  			log.Fatal(err)
   980  		}
   981  		if stream.ID() == 0 {
   982  			break
   983  		}
   984  	}
   985  }
   986  
   987  func ExampleChangeStream_ResumeToken() {
   988  	var client *mongo.Client
   989  
   990  	// Assume stream was created via client.Watch()
   991  	var stream *mongo.ChangeStream
   992  
   993  	cancelCtx, cancel := context.WithCancel(context.TODO())
   994  	defer cancel()
   995  	var wg sync.WaitGroup
   996  	wg.Add(1)
   997  
   998  	// Run a goroutine to process events.
   999  	go func() {
  1000  		for stream.Next(cancelCtx) {
  1001  			fmt.Println(stream.Current)
  1002  		}
  1003  		wg.Done()
  1004  	}()
  1005  
  1006  	// Assume client needs to be disconnected. Cancel the context being used by
  1007  	// the goroutine to abort any in-progres Next calls and wait for the
  1008  	// goroutine to exit.
  1009  	cancel()
  1010  	wg.Wait()
  1011  
  1012  	// Before disconnecting the client, store the last seen resume token for the
  1013  	// change stream.
  1014  	resumeToken := stream.ResumeToken()
  1015  	_ = client.Disconnect(context.TODO())
  1016  
  1017  	// Once a new client is created, the change stream can be re-created.
  1018  	// Specify resumeToken as the ResumeAfter option so only events that
  1019  	// occurred after resumeToken will be returned.
  1020  	var newClient *mongo.Client
  1021  	opts := options.ChangeStream().SetResumeAfter(resumeToken)
  1022  	newStream, err := newClient.Watch(context.TODO(), mongo.Pipeline{}, opts)
  1023  	if err != nil {
  1024  		log.Fatal(err)
  1025  	}
  1026  	defer newStream.Close(context.TODO())
  1027  }
  1028  
  1029  // IndexView examples
  1030  
  1031  func ExampleIndexView_CreateMany() {
  1032  	var indexView *mongo.IndexView
  1033  
  1034  	// Create two indexes: {name: 1, email: 1} and {name: 1, age: 1}
  1035  	// For the first index, specify no options. The name will be generated as
  1036  	// "name_1_email_1" by the driver.
  1037  	// For the second index, specify the Name option to explicitly set the name
  1038  	// to "nameAge".
  1039  	models := []mongo.IndexModel{
  1040  		{
  1041  			Keys: bson.D{{"name", 1}, {"email", 1}},
  1042  		},
  1043  		{
  1044  			Keys:    bson.D{{"name", 1}, {"age", 1}},
  1045  			Options: options.Index().SetName("nameAge"),
  1046  		},
  1047  	}
  1048  
  1049  	// Specify the MaxTime option to limit the amount of time the operation can
  1050  	// run on the server
  1051  	opts := options.CreateIndexes().SetMaxTime(2 * time.Second)
  1052  	names, err := indexView.CreateMany(context.TODO(), models, opts)
  1053  	if err != nil {
  1054  		log.Fatal(err)
  1055  	}
  1056  
  1057  	fmt.Printf("created indexes %v\n", names)
  1058  }
  1059  
  1060  func ExampleIndexView_List() {
  1061  	var indexView *mongo.IndexView
  1062  
  1063  	// Specify the MaxTime option to limit the amount of time the operation can
  1064  	// run on the server
  1065  	opts := options.ListIndexes().SetMaxTime(2 * time.Second)
  1066  	cursor, err := indexView.List(context.TODO(), opts)
  1067  	if err != nil {
  1068  		log.Fatal(err)
  1069  	}
  1070  
  1071  	// Get a slice of all indexes returned and print them out.
  1072  	var results []bson.M
  1073  	if err = cursor.All(context.TODO(), &results); err != nil {
  1074  		log.Fatal(err)
  1075  	}
  1076  	fmt.Println(results)
  1077  }
  1078  
  1079  func ExampleCollection_Find_primitiveRegex() {
  1080  	ctx := context.TODO()
  1081  	clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
  1082  
  1083  	// Connect to a mongodb server.
  1084  	client, err := mongo.Connect(ctx, clientOptions)
  1085  	if err != nil {
  1086  		panic(err)
  1087  	}
  1088  
  1089  	defer func() { _ = client.Disconnect(ctx) }()
  1090  
  1091  	type Pet struct {
  1092  		Type string `bson:"type"`
  1093  		Name string `bson:"name"`
  1094  	}
  1095  
  1096  	// Create a slice of documents to insert. We will lookup a subset of
  1097  	// these documents using regex.
  1098  	toInsert := []interface{}{
  1099  		Pet{Type: "cat", Name: "Mo"},
  1100  		Pet{Type: "dog", Name: "Loki"},
  1101  	}
  1102  
  1103  	coll := client.Database("test").Collection("test")
  1104  
  1105  	if _, err := coll.InsertMany(ctx, toInsert); err != nil {
  1106  		panic(err)
  1107  	}
  1108  
  1109  	// Create a filter to find a document with key "name" and any value that
  1110  	// starts with letter "m". Use the "i" option to indicate
  1111  	// case-insensitivity.
  1112  	filter := bson.D{{"name", primitive.Regex{Pattern: "^m", Options: "i"}}}
  1113  
  1114  	_, err = coll.Find(ctx, filter)
  1115  	if err != nil {
  1116  		panic(err)
  1117  	}
  1118  }
  1119  
  1120  func ExampleCollection_Find_regex() {
  1121  	ctx := context.TODO()
  1122  	clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
  1123  
  1124  	// Connect to a mongodb server.
  1125  	client, err := mongo.Connect(ctx, clientOptions)
  1126  	if err != nil {
  1127  		panic(err)
  1128  	}
  1129  
  1130  	defer func() { _ = client.Disconnect(ctx) }()
  1131  
  1132  	type Pet struct {
  1133  		Type string `bson:"type"`
  1134  		Name string `bson:"name"`
  1135  	}
  1136  
  1137  	// Create a slice of documents to insert. We will lookup a subset of
  1138  	// these documents using regex.
  1139  	toInsert := []interface{}{
  1140  		Pet{Type: "cat", Name: "Mo"},
  1141  		Pet{Type: "dog", Name: "Loki"},
  1142  	}
  1143  
  1144  	coll := client.Database("test").Collection("test")
  1145  
  1146  	if _, err := coll.InsertMany(ctx, toInsert); err != nil {
  1147  		panic(err)
  1148  	}
  1149  
  1150  	// Create a filter to find a document with key "name" and any value that
  1151  	// starts with letter "m". Use the "i" option to indicate
  1152  	// case-insensitivity.
  1153  	filter := bson.D{{"name", bson.D{{"$regex", "^m"}, {"$options", "i"}}}}
  1154  
  1155  	_, err = coll.Find(ctx, filter)
  1156  	if err != nil {
  1157  		panic(err)
  1158  	}
  1159  }
  1160  

View as plain text