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