1
2
3
4
5
6
7 package documentation_examples
8
9 import (
10 "context"
11 "fmt"
12 "io/ioutil"
13 logger "log"
14 "strings"
15 "sync/atomic"
16 "testing"
17 "time"
18
19 "go.mongodb.org/mongo-driver/bson"
20 "go.mongodb.org/mongo-driver/bson/primitive"
21 "go.mongodb.org/mongo-driver/internal/assert"
22 "go.mongodb.org/mongo-driver/mongo"
23 "go.mongodb.org/mongo-driver/mongo/integration/mtest"
24 "go.mongodb.org/mongo-driver/mongo/options"
25 "go.mongodb.org/mongo-driver/mongo/readconcern"
26 "go.mongodb.org/mongo-driver/mongo/readpref"
27 "go.mongodb.org/mongo-driver/mongo/writeconcern"
28 )
29
30 func requireCursorLength(t *testing.T, cursor *mongo.Cursor, length int) {
31 i := 0
32 for cursor.Next(context.Background()) {
33 i++
34 }
35
36 assert.NoError(t, cursor.Err())
37 assert.Equal(t, i, length)
38 }
39
40 func containsKey(doc bson.Raw, key ...string) bool {
41 _, err := doc.LookupErr(key...)
42 return err == nil
43 }
44
45 func parseDate(t *testing.T, dateString string) time.Time {
46 rfc3339MilliLayout := "2006-01-02T15:04:05.999Z07:00"
47 parsedDate, err := time.Parse(rfc3339MilliLayout, dateString)
48
49 assert.NoError(t, err)
50 return parsedDate
51 }
52
53
54
55 func InsertExamples(t *testing.T, db *mongo.Database) {
56 coll := db.Collection("inventory_insert")
57
58 err := coll.Drop(context.Background())
59 assert.NoError(t, err)
60
61 {
62
63
64 result, err := coll.InsertOne(
65 context.TODO(),
66 bson.D{
67 {"item", "canvas"},
68 {"qty", 100},
69 {"tags", bson.A{"cotton"}},
70 {"size", bson.D{
71 {"h", 28},
72 {"w", 35.5},
73 {"uom", "cm"},
74 }},
75 })
76
77
78
79 assert.NoError(t, err)
80 assert.NotNil(t, result.InsertedID)
81 }
82
83 {
84
85
86 cursor, err := coll.Find(
87 context.TODO(),
88 bson.D{{"item", "canvas"}},
89 )
90
91
92
93 assert.NoError(t, err)
94 requireCursorLength(t, cursor, 1)
95 }
96
97 {
98
99
100 result, err := coll.InsertMany(
101 context.TODO(),
102 []interface{}{
103 bson.D{
104 {"item", "journal"},
105 {"qty", int32(25)},
106 {"tags", bson.A{"blank", "red"}},
107 {"size", bson.D{
108 {"h", 14},
109 {"w", 21},
110 {"uom", "cm"},
111 }},
112 },
113 bson.D{
114 {"item", "mat"},
115 {"qty", int32(25)},
116 {"tags", bson.A{"gray"}},
117 {"size", bson.D{
118 {"h", 27.9},
119 {"w", 35.5},
120 {"uom", "cm"},
121 }},
122 },
123 bson.D{
124 {"item", "mousepad"},
125 {"qty", 25},
126 {"tags", bson.A{"gel", "blue"}},
127 {"size", bson.D{
128 {"h", 19},
129 {"w", 22.85},
130 {"uom", "cm"},
131 }},
132 },
133 })
134
135
136
137 assert.NoError(t, err)
138 assert.Len(t, result.InsertedIDs, 3)
139 }
140 }
141
142
143
144 func QueryToplevelFieldsExamples(t *testing.T, db *mongo.Database) {
145 coll := db.Collection("inventory_query_top")
146
147 err := coll.Drop(context.Background())
148 assert.NoError(t, err)
149
150 {
151
152
153 docs := []interface{}{
154 bson.D{
155 {"item", "journal"},
156 {"qty", 25},
157 {"size", bson.D{
158 {"h", 14},
159 {"w", 21},
160 {"uom", "cm"},
161 }},
162 {"status", "A"},
163 },
164 bson.D{
165 {"item", "notebook"},
166 {"qty", 50},
167 {"size", bson.D{
168 {"h", 8.5},
169 {"w", 11},
170 {"uom", "in"},
171 }},
172 {"status", "A"},
173 },
174 bson.D{
175 {"item", "paper"},
176 {"qty", 100},
177 {"size", bson.D{
178 {"h", 8.5},
179 {"w", 11},
180 {"uom", "in"},
181 }},
182 {"status", "D"},
183 },
184 bson.D{
185 {"item", "planner"},
186 {"qty", 75},
187 {"size", bson.D{
188 {"h", 22.85},
189 {"w", 30},
190 {"uom", "cm"},
191 }},
192 {"status", "D"},
193 },
194 bson.D{
195 {"item", "postcard"},
196 {"qty", 45},
197 {"size", bson.D{
198 {"h", 10},
199 {"w", 15.25},
200 {"uom", "cm"},
201 }},
202 {"status", "A"},
203 },
204 }
205
206 result, err := coll.InsertMany(context.TODO(), docs)
207
208
209
210 assert.NoError(t, err)
211 assert.Len(t, result.InsertedIDs, 5)
212 }
213
214 {
215
216
217 cursor, err := coll.Find(
218 context.TODO(),
219 bson.D{},
220 )
221
222
223
224 assert.NoError(t, err)
225 requireCursorLength(t, cursor, 5)
226 }
227
228 {
229
230
231 cursor, err := coll.Find(
232 context.TODO(),
233 bson.D{{"status", "D"}},
234 )
235
236
237
238 assert.NoError(t, err)
239 requireCursorLength(t, cursor, 2)
240 }
241
242 {
243
244
245 cursor, err := coll.Find(
246 context.TODO(),
247 bson.D{{"status", bson.D{{"$in", bson.A{"A", "D"}}}}})
248
249
250
251 assert.NoError(t, err)
252 requireCursorLength(t, cursor, 5)
253 }
254
255 {
256
257
258 cursor, err := coll.Find(
259 context.TODO(),
260 bson.D{
261 {"status", "A"},
262 {"qty", bson.D{{"$lt", 30}}},
263 })
264
265
266
267 assert.NoError(t, err)
268 requireCursorLength(t, cursor, 1)
269 }
270
271 {
272
273
274 cursor, err := coll.Find(
275 context.TODO(),
276 bson.D{
277 {"$or",
278 bson.A{
279 bson.D{{"status", "A"}},
280 bson.D{{"qty", bson.D{{"$lt", 30}}}},
281 }},
282 })
283
284
285
286 assert.NoError(t, err)
287 requireCursorLength(t, cursor, 3)
288 }
289
290 {
291
292
293 cursor, err := coll.Find(
294 context.TODO(),
295 bson.D{
296 {"status", "A"},
297 {"$or", bson.A{
298 bson.D{{"qty", bson.D{{"$lt", 30}}}},
299 bson.D{{"item", primitive.Regex{Pattern: "^p", Options: ""}}},
300 }},
301 })
302
303
304
305 assert.NoError(t, err)
306 requireCursorLength(t, cursor, 2)
307 }
308
309 }
310
311
312
313 func QueryEmbeddedDocumentsExamples(t *testing.T, db *mongo.Database) {
314 coll := db.Collection("inventory_query_embedded")
315
316 err := coll.Drop(context.Background())
317 assert.NoError(t, err)
318
319 {
320
321
322 docs := []interface{}{
323 bson.D{
324 {"item", "journal"},
325 {"qty", 25},
326 {"size", bson.D{
327 {"h", 14},
328 {"w", 21},
329 {"uom", "cm"},
330 }},
331 {"status", "A"},
332 },
333 bson.D{
334 {"item", "notebook"},
335 {"qty", 50},
336 {"size", bson.D{
337 {"h", 8.5},
338 {"w", 11},
339 {"uom", "in"},
340 }},
341 {"status", "A"},
342 },
343 bson.D{
344 {"item", "paper"},
345 {"qty", 100},
346 {"size", bson.D{
347 {"h", 8.5},
348 {"w", 11},
349 {"uom", "in"},
350 }},
351 {"status", "D"},
352 },
353 bson.D{
354 {"item", "planner"},
355 {"qty", 75},
356 {"size", bson.D{
357 {"h", 22.85},
358 {"w", 30},
359 {"uom", "cm"},
360 }},
361 {"status", "D"},
362 },
363 bson.D{
364 {"item", "postcard"},
365 {"qty", 45},
366 {"size", bson.D{
367 {"h", 10},
368 {"w", 15.25},
369 {"uom", "cm"},
370 }},
371 {"status", "A"},
372 },
373 }
374
375 result, err := coll.InsertMany(context.TODO(), docs)
376
377
378
379 assert.NoError(t, err)
380 assert.Len(t, result.InsertedIDs, 5)
381 }
382
383 {
384
385
386 cursor, err := coll.Find(
387 context.TODO(),
388 bson.D{
389 {"size", bson.D{
390 {"h", 14},
391 {"w", 21},
392 {"uom", "cm"},
393 }},
394 })
395
396
397
398 assert.NoError(t, err)
399 requireCursorLength(t, cursor, 1)
400 }
401
402 {
403
404
405 cursor, err := coll.Find(
406 context.TODO(),
407 bson.D{
408 {"size", bson.D{
409 {"w", 21},
410 {"h", 14},
411 {"uom", "cm"},
412 }},
413 })
414
415
416
417 assert.NoError(t, err)
418 requireCursorLength(t, cursor, 0)
419 }
420
421 {
422
423
424 cursor, err := coll.Find(
425 context.TODO(),
426 bson.D{{"size.uom", "in"}},
427 )
428
429
430
431 assert.NoError(t, err)
432 requireCursorLength(t, cursor, 2)
433 }
434
435 {
436
437
438 cursor, err := coll.Find(
439 context.TODO(),
440 bson.D{
441 {"size.h", bson.D{
442 {"$lt", 15},
443 }},
444 })
445
446
447
448 assert.NoError(t, err)
449 requireCursorLength(t, cursor, 4)
450 }
451
452 {
453
454
455 cursor, err := coll.Find(
456 context.TODO(),
457 bson.D{
458 {"size.h", bson.D{
459 {"$lt", 15},
460 }},
461 {"size.uom", "in"},
462 {"status", "D"},
463 })
464
465
466
467 assert.NoError(t, err)
468 requireCursorLength(t, cursor, 1)
469 }
470
471 }
472
473
474
475 func QueryArraysExamples(t *testing.T, db *mongo.Database) {
476 coll := db.Collection("inventory_query_array")
477
478 err := coll.Drop(context.Background())
479 assert.NoError(t, err)
480
481 {
482
483
484 docs := []interface{}{
485 bson.D{
486 {"item", "journal"},
487 {"qty", 25},
488 {"tags", bson.A{"blank", "red"}},
489 {"dim_cm", bson.A{14, 21}},
490 },
491 bson.D{
492 {"item", "notebook"},
493 {"qty", 50},
494 {"tags", bson.A{"red", "blank"}},
495 {"dim_cm", bson.A{14, 21}},
496 },
497 bson.D{
498 {"item", "paper"},
499 {"qty", 100},
500 {"tags", bson.A{"red", "blank", "plain"}},
501 {"dim_cm", bson.A{14, 21}},
502 },
503 bson.D{
504 {"item", "planner"},
505 {"qty", 75},
506 {"tags", bson.A{"blank", "red"}},
507 {"dim_cm", bson.A{22.85, 30}},
508 },
509 bson.D{
510 {"item", "postcard"},
511 {"qty", 45},
512 {"tags", bson.A{"blue"}},
513 {"dim_cm", bson.A{10, 15.25}},
514 },
515 }
516
517 result, err := coll.InsertMany(context.TODO(), docs)
518
519
520
521 assert.NoError(t, err)
522 assert.Len(t, result.InsertedIDs, 5)
523 }
524
525 {
526
527
528 cursor, err := coll.Find(
529 context.TODO(),
530 bson.D{{"tags", bson.A{"red", "blank"}}},
531 )
532
533
534
535 assert.NoError(t, err)
536 requireCursorLength(t, cursor, 1)
537 }
538
539 {
540
541
542 cursor, err := coll.Find(
543 context.TODO(),
544 bson.D{
545 {"tags", bson.D{{"$all", bson.A{"red", "blank"}}}},
546 })
547
548
549
550 assert.NoError(t, err)
551 requireCursorLength(t, cursor, 4)
552 }
553
554 {
555
556
557 cursor, err := coll.Find(
558 context.TODO(),
559 bson.D{
560 {"tags", "red"},
561 })
562
563
564
565 assert.NoError(t, err)
566 requireCursorLength(t, cursor, 4)
567 }
568
569 {
570
571
572 cursor, err := coll.Find(
573 context.TODO(),
574 bson.D{
575 {"dim_cm", bson.D{
576 {"$gt", 25},
577 }},
578 })
579
580
581
582 assert.NoError(t, err)
583 requireCursorLength(t, cursor, 1)
584 }
585
586 {
587
588
589 cursor, err := coll.Find(
590 context.TODO(),
591 bson.D{
592 {"dim_cm", bson.D{
593 {"$gt", 15},
594 {"$lt", 20},
595 }},
596 })
597
598
599
600 assert.NoError(t, err)
601 requireCursorLength(t, cursor, 4)
602 }
603
604 {
605
606
607 cursor, err := coll.Find(
608 context.TODO(),
609 bson.D{
610 {"dim_cm", bson.D{
611 {"$elemMatch", bson.D{
612 {"$gt", 22},
613 {"$lt", 30},
614 }},
615 }},
616 })
617
618
619
620 assert.NoError(t, err)
621 requireCursorLength(t, cursor, 1)
622 }
623
624 {
625
626
627 cursor, err := coll.Find(
628 context.TODO(),
629 bson.D{
630 {"dim_cm.1", bson.D{
631 {"$gt", 25},
632 }},
633 })
634
635
636
637 assert.NoError(t, err)
638 requireCursorLength(t, cursor, 1)
639 }
640
641 {
642
643
644 cursor, err := coll.Find(
645 context.TODO(),
646 bson.D{
647 {"tags", bson.D{
648 {"$size", 3},
649 }},
650 })
651
652
653
654 assert.NoError(t, err)
655 requireCursorLength(t, cursor, 1)
656 }
657
658 }
659
660
661
662 func QueryArrayEmbeddedDocumentsExamples(t *testing.T, db *mongo.Database) {
663 coll := db.Collection("inventory_query_array_embedded")
664
665 err := coll.Drop(context.Background())
666 assert.NoError(t, err)
667
668 {
669
670
671 docs := []interface{}{
672 bson.D{
673 {"item", "journal"},
674 {"instock", bson.A{
675 bson.D{
676 {"warehouse", "A"},
677 {"qty", 5},
678 },
679 bson.D{
680 {"warehouse", "C"},
681 {"qty", 15},
682 },
683 }},
684 },
685 bson.D{
686 {"item", "notebook"},
687 {"instock", bson.A{
688 bson.D{
689 {"warehouse", "C"},
690 {"qty", 5},
691 },
692 }},
693 },
694 bson.D{
695 {"item", "paper"},
696 {"instock", bson.A{
697 bson.D{
698 {"warehouse", "A"},
699 {"qty", 60},
700 },
701 bson.D{
702 {"warehouse", "B"},
703 {"qty", 15},
704 },
705 }},
706 },
707 bson.D{
708 {"item", "planner"},
709 {"instock", bson.A{
710 bson.D{
711 {"warehouse", "A"},
712 {"qty", 40},
713 },
714 bson.D{
715 {"warehouse", "B"},
716 {"qty", 5},
717 },
718 }},
719 },
720 bson.D{
721 {"item", "postcard"},
722 {"instock", bson.A{
723 bson.D{
724 {"warehouse", "B"},
725 {"qty", 15},
726 },
727 bson.D{
728 {"warehouse", "C"},
729 {"qty", 35},
730 },
731 }},
732 },
733 }
734
735 result, err := coll.InsertMany(context.TODO(), docs)
736
737
738
739 assert.NoError(t, err)
740 assert.Len(t, result.InsertedIDs, 5)
741 }
742
743 {
744
745
746 cursor, err := coll.Find(
747 context.TODO(),
748 bson.D{
749 {"instock", bson.D{
750 {"warehouse", "A"},
751 {"qty", 5},
752 }},
753 })
754
755
756
757 assert.NoError(t, err)
758 requireCursorLength(t, cursor, 1)
759 }
760
761 {
762
763
764 cursor, err := coll.Find(
765 context.TODO(),
766 bson.D{
767 {"instock", bson.D{
768 {"qty", 5},
769 {"warehouse", "A"},
770 }},
771 })
772
773
774
775 assert.NoError(t, err)
776 requireCursorLength(t, cursor, 0)
777 }
778
779 {
780
781
782 cursor, err := coll.Find(
783 context.TODO(),
784 bson.D{
785 {"instock.0.qty", bson.D{
786 {"$lte", 20},
787 }},
788 })
789
790
791
792 assert.NoError(t, err)
793 requireCursorLength(t, cursor, 3)
794 }
795
796 {
797
798
799 cursor, err := coll.Find(
800 context.TODO(),
801 bson.D{
802 {"instock.qty", bson.D{
803 {"$lte", 20},
804 }},
805 })
806
807
808
809 assert.NoError(t, err)
810 requireCursorLength(t, cursor, 5)
811 }
812
813 {
814
815
816 cursor, err := coll.Find(
817 context.TODO(),
818 bson.D{
819 {"instock", bson.D{
820 {"$elemMatch", bson.D{
821 {"qty", 5},
822 {"warehouse", "A"},
823 }},
824 }},
825 })
826
827
828
829 assert.NoError(t, err)
830 requireCursorLength(t, cursor, 1)
831 }
832
833 {
834
835
836 cursor, err := coll.Find(
837 context.TODO(),
838 bson.D{
839 {"instock", bson.D{
840 {"$elemMatch", bson.D{
841 {"qty", bson.D{
842 {"$gt", 10},
843 {"$lte", 20},
844 }},
845 }},
846 }},
847 })
848
849
850
851 assert.NoError(t, err)
852 requireCursorLength(t, cursor, 3)
853 }
854
855 {
856
857
858 cursor, err := coll.Find(
859 context.TODO(),
860 bson.D{
861 {"instock.qty", bson.D{
862 {"$gt", 10},
863 {"$lte", 20},
864 }},
865 })
866
867
868
869 assert.NoError(t, err)
870 requireCursorLength(t, cursor, 4)
871 }
872
873 {
874
875
876 cursor, err := coll.Find(
877 context.TODO(),
878 bson.D{
879 {"instock.qty", 5},
880 {"instock.warehouse", "A"},
881 })
882
883
884
885 assert.NoError(t, err)
886 requireCursorLength(t, cursor, 2)
887 }
888 }
889
890
891
892 func QueryNullMissingFieldsExamples(t *testing.T, db *mongo.Database) {
893 coll := db.Collection("inventory_query_null_missing")
894
895 err := coll.Drop(context.Background())
896 assert.NoError(t, err)
897
898 {
899
900
901 docs := []interface{}{
902 bson.D{
903 {"_id", 1},
904 {"item", nil},
905 },
906 bson.D{
907 {"_id", 2},
908 },
909 }
910
911 result, err := coll.InsertMany(context.TODO(), docs)
912
913
914
915 assert.NoError(t, err)
916 assert.Len(t, result.InsertedIDs, 2)
917 }
918
919 {
920
921
922 cursor, err := coll.Find(
923 context.TODO(),
924 bson.D{
925 {"item", nil},
926 })
927
928
929
930 assert.NoError(t, err)
931 requireCursorLength(t, cursor, 2)
932 }
933
934 {
935
936
937 cursor, err := coll.Find(
938 context.TODO(),
939 bson.D{
940 {"item", bson.D{
941 {"$type", 10},
942 }},
943 })
944
945
946
947 assert.NoError(t, err)
948 requireCursorLength(t, cursor, 1)
949 }
950
951 {
952
953
954 cursor, err := coll.Find(
955 context.TODO(),
956 bson.D{
957 {"item", bson.D{
958 {"$exists", false},
959 }},
960 })
961
962
963
964 assert.NoError(t, err)
965 requireCursorLength(t, cursor, 1)
966 }
967 }
968
969
970
971 func ProjectionExamples(t *testing.T, db *mongo.Database) {
972 coll := db.Collection("inventory_project")
973
974 err := coll.Drop(context.Background())
975 assert.NoError(t, err)
976
977 {
978
979
980 docs := []interface{}{
981 bson.D{
982 {"item", "journal"},
983 {"status", "A"},
984 {"size", bson.D{
985 {"h", 14},
986 {"w", 21},
987 {"uom", "cm"},
988 }},
989 {"instock", bson.A{
990 bson.D{
991 {"warehouse", "A"},
992 {"qty", 5},
993 },
994 }},
995 },
996 bson.D{
997 {"item", "notebook"},
998 {"status", "A"},
999 {"size", bson.D{
1000 {"h", 8.5},
1001 {"w", 11},
1002 {"uom", "in"},
1003 }},
1004 {"instock", bson.A{
1005 bson.D{
1006 {"warehouse", "EC"},
1007 {"qty", 5},
1008 },
1009 }},
1010 },
1011 bson.D{
1012 {"item", "paper"},
1013 {"status", "D"},
1014 {"size", bson.D{
1015 {"h", 8.5},
1016 {"w", 11},
1017 {"uom", "in"},
1018 }},
1019 {"instock", bson.A{
1020 bson.D{
1021 {"warehouse", "A"},
1022 {"qty", 60},
1023 },
1024 }},
1025 },
1026 bson.D{
1027 {"item", "planner"},
1028 {"status", "D"},
1029 {"size", bson.D{
1030 {"h", 22.85},
1031 {"w", 30},
1032 {"uom", "cm"},
1033 }},
1034 {"instock", bson.A{
1035 bson.D{
1036 {"warehouse", "A"},
1037 {"qty", 40},
1038 },
1039 }},
1040 },
1041 bson.D{
1042 {"item", "postcard"},
1043 {"status", "A"},
1044 {"size", bson.D{
1045 {"h", 10},
1046 {"w", 15.25},
1047 {"uom", "cm"},
1048 }},
1049 {"instock", bson.A{
1050 bson.D{
1051 {"warehouse", "B"},
1052 {"qty", 15},
1053 },
1054 bson.D{
1055 {"warehouse", "EC"},
1056 {"qty", 35},
1057 },
1058 }},
1059 },
1060 }
1061
1062 result, err := coll.InsertMany(context.TODO(), docs)
1063
1064
1065
1066 assert.NoError(t, err)
1067 assert.Len(t, result.InsertedIDs, 5)
1068 }
1069
1070 {
1071
1072
1073 cursor, err := coll.Find(
1074 context.TODO(),
1075 bson.D{{"status", "A"}},
1076 )
1077
1078
1079
1080 assert.NoError(t, err)
1081 requireCursorLength(t, cursor, 3)
1082 }
1083
1084 {
1085
1086
1087 projection := bson.D{
1088 {"item", 1},
1089 {"status", 1},
1090 }
1091
1092 cursor, err := coll.Find(
1093 context.TODO(),
1094 bson.D{
1095 {"status", "A"},
1096 },
1097 options.Find().SetProjection(projection),
1098 )
1099
1100
1101
1102 assert.NoError(t, err)
1103
1104 for cursor.Next(context.Background()) {
1105 doc := cursor.Current
1106
1107 assert.True(t, containsKey(doc, "_id"))
1108 assert.True(t, containsKey(doc, "item"))
1109 assert.True(t, containsKey(doc, "status"))
1110 assert.False(t, containsKey(doc, "size"))
1111 assert.False(t, containsKey(doc, "instock"))
1112 }
1113
1114 assert.NoError(t, cursor.Err())
1115 }
1116
1117 {
1118
1119
1120 projection := bson.D{
1121 {"item", 1},
1122 {"status", 1},
1123 {"_id", 0},
1124 }
1125
1126 cursor, err := coll.Find(
1127 context.TODO(),
1128 bson.D{
1129 {"status", "A"},
1130 },
1131 options.Find().SetProjection(projection),
1132 )
1133
1134
1135
1136 assert.NoError(t, err)
1137
1138 for cursor.Next(context.Background()) {
1139 doc := cursor.Current
1140
1141 assert.False(t, containsKey(doc, "_id"))
1142 assert.True(t, containsKey(doc, "item"))
1143 assert.True(t, containsKey(doc, "status"))
1144 assert.False(t, containsKey(doc, "size"))
1145 assert.False(t, containsKey(doc, "instock"))
1146 }
1147
1148 assert.NoError(t, cursor.Err())
1149 }
1150
1151 {
1152
1153
1154 projection := bson.D{
1155 {"status", 0},
1156 {"instock", 0},
1157 }
1158
1159 cursor, err := coll.Find(
1160 context.TODO(),
1161 bson.D{
1162 {"status", "A"},
1163 },
1164 options.Find().SetProjection(projection),
1165 )
1166
1167
1168
1169 assert.NoError(t, err)
1170
1171 for cursor.Next(context.Background()) {
1172 doc := cursor.Current
1173
1174 assert.True(t, containsKey(doc, "_id"))
1175 assert.True(t, containsKey(doc, "item"))
1176 assert.False(t, containsKey(doc, "status"))
1177 assert.True(t, containsKey(doc, "size"))
1178 assert.False(t, containsKey(doc, "instock"))
1179 }
1180
1181 assert.NoError(t, cursor.Err())
1182 }
1183
1184 {
1185
1186
1187 projection := bson.D{
1188 {"item", 1},
1189 {"status", 1},
1190 {"size.uom", 1},
1191 }
1192
1193 cursor, err := coll.Find(
1194 context.TODO(),
1195 bson.D{
1196 {"status", "A"},
1197 },
1198 options.Find().SetProjection(projection),
1199 )
1200
1201
1202
1203 assert.NoError(t, err)
1204
1205 for cursor.Next(context.Background()) {
1206 doc := cursor.Current
1207
1208 assert.True(t, containsKey(doc, "_id"))
1209 assert.True(t, containsKey(doc, "item"))
1210 assert.True(t, containsKey(doc, "status"))
1211 assert.True(t, containsKey(doc, "size"))
1212 assert.False(t, containsKey(doc, "instock"))
1213
1214 assert.True(t, containsKey(doc, "size", "uom"))
1215 assert.False(t, containsKey(doc, "size", "h"))
1216 assert.False(t, containsKey(doc, "size", "w"))
1217
1218 }
1219
1220 assert.NoError(t, cursor.Err())
1221 }
1222
1223 {
1224
1225
1226 projection := bson.D{
1227 {"size.uom", 0},
1228 }
1229
1230 cursor, err := coll.Find(
1231 context.TODO(),
1232 bson.D{
1233 {"status", "A"},
1234 },
1235 options.Find().SetProjection(projection),
1236 )
1237
1238
1239
1240 assert.NoError(t, err)
1241
1242 for cursor.Next(context.Background()) {
1243 doc := cursor.Current
1244
1245 assert.True(t, containsKey(doc, "_id"))
1246 assert.True(t, containsKey(doc, "item"))
1247 assert.True(t, containsKey(doc, "status"))
1248 assert.True(t, containsKey(doc, "size"))
1249 assert.True(t, containsKey(doc, "instock"))
1250
1251 assert.False(t, containsKey(doc, "size", "uom"))
1252 assert.True(t, containsKey(doc, "size", "h"))
1253 assert.True(t, containsKey(doc, "size", "w"))
1254
1255 }
1256
1257 assert.NoError(t, cursor.Err())
1258 }
1259
1260 {
1261
1262
1263 projection := bson.D{
1264 {"item", 1},
1265 {"status", 1},
1266 {"instock.qty", 1},
1267 }
1268
1269 cursor, err := coll.Find(
1270 context.TODO(),
1271 bson.D{
1272 {"status", "A"},
1273 },
1274 options.Find().SetProjection(projection),
1275 )
1276
1277
1278
1279 assert.NoError(t, err)
1280
1281 for cursor.Next(context.Background()) {
1282 doc := cursor.Current
1283
1284 assert.True(t, containsKey(doc, "_id"))
1285 assert.True(t, containsKey(doc, "item"))
1286 assert.True(t, containsKey(doc, "status"))
1287 assert.False(t, containsKey(doc, "size"))
1288 assert.True(t, containsKey(doc, "instock"))
1289
1290 instock, err := doc.LookupErr("instock")
1291 assert.NoError(t, err)
1292
1293 vals, err := instock.Array().Values()
1294 assert.NoError(t, err)
1295
1296 for _, val := range vals {
1297 assert.Equal(t, bson.TypeEmbeddedDocument, val.Type)
1298 subdoc := val.Document()
1299 elems, err := subdoc.Elements()
1300 assert.NoError(t, err)
1301
1302 assert.Equal(t, 1, len(elems))
1303 _, err = subdoc.LookupErr("qty")
1304 assert.NoError(t, err)
1305 }
1306 }
1307
1308 assert.NoError(t, cursor.Err())
1309 }
1310
1311 {
1312
1313
1314 projection := bson.D{
1315 {"item", 1},
1316 {"status", 1},
1317 {"instock", bson.D{
1318 {"$slice", -1},
1319 }},
1320 }
1321
1322 cursor, err := coll.Find(
1323 context.TODO(),
1324 bson.D{
1325 {"status", "A"},
1326 },
1327 options.Find().SetProjection(projection),
1328 )
1329
1330
1331
1332 assert.NoError(t, err)
1333
1334 for cursor.Next(context.Background()) {
1335 doc := cursor.Current
1336
1337 assert.True(t, containsKey(doc, "_id"))
1338 assert.True(t, containsKey(doc, "item"))
1339 assert.True(t, containsKey(doc, "status"))
1340 assert.False(t, containsKey(doc, "size"))
1341 assert.True(t, containsKey(doc, "instock"))
1342
1343 instock, err := doc.LookupErr("instock")
1344 assert.NoError(t, err)
1345 vals, err := instock.Array().Values()
1346 assert.NoError(t, err)
1347 assert.Equal(t, len(vals), 1)
1348 }
1349
1350 assert.NoError(t, cursor.Err())
1351 }
1352 }
1353
1354
1355
1356 func UpdateExamples(t *testing.T, db *mongo.Database) {
1357 coll := db.Collection("inventory_update")
1358
1359 err := coll.Drop(context.Background())
1360 assert.NoError(t, err)
1361
1362 {
1363
1364
1365 docs := []interface{}{
1366 bson.D{
1367 {"item", "canvas"},
1368 {"qty", 100},
1369 {"size", bson.D{
1370 {"h", 28},
1371 {"w", 35.5},
1372 {"uom", "cm"},
1373 }},
1374 {"status", "A"},
1375 },
1376 bson.D{
1377 {"item", "journal"},
1378 {"qty", 25},
1379 {"size", bson.D{
1380 {"h", 14},
1381 {"w", 21},
1382 {"uom", "cm"},
1383 }},
1384 {"status", "A"},
1385 },
1386 bson.D{
1387 {"item", "mat"},
1388 {"qty", 85},
1389 {"size", bson.D{
1390 {"h", 27.9},
1391 {"w", 35.5},
1392 {"uom", "cm"},
1393 }},
1394 {"status", "A"},
1395 },
1396 bson.D{
1397 {"item", "mousepad"},
1398 {"qty", 25},
1399 {"size", bson.D{
1400 {"h", 19},
1401 {"w", 22.85},
1402 {"uom", "in"},
1403 }},
1404 {"status", "P"},
1405 },
1406 bson.D{
1407 {"item", "notebook"},
1408 {"qty", 50},
1409 {"size", bson.D{
1410 {"h", 8.5},
1411 {"w", 11},
1412 {"uom", "in"},
1413 }},
1414 {"status", "P"},
1415 },
1416 bson.D{
1417 {"item", "paper"},
1418 {"qty", 100},
1419 {"size", bson.D{
1420 {"h", 8.5},
1421 {"w", 11},
1422 {"uom", "in"},
1423 }},
1424 {"status", "D"},
1425 },
1426 bson.D{
1427 {"item", "planner"},
1428 {"qty", 75},
1429 {"size", bson.D{
1430 {"h", 22.85},
1431 {"w", 30},
1432 {"uom", "cm"},
1433 }},
1434 {"status", "D"},
1435 },
1436 bson.D{
1437 {"item", "postcard"},
1438 {"qty", 45},
1439 {"size", bson.D{
1440 {"h", 10},
1441 {"w", 15.25},
1442 {"uom", "cm"},
1443 }},
1444 {"status", "A"},
1445 },
1446 bson.D{
1447 {"item", "sketchbook"},
1448 {"qty", 80},
1449 {"size", bson.D{
1450 {"h", 14},
1451 {"w", 21},
1452 {"uom", "cm"},
1453 }},
1454 {"status", "A"},
1455 },
1456 bson.D{
1457 {"item", "sketch pad"},
1458 {"qty", 95},
1459 {"size", bson.D{
1460 {"h", 22.85},
1461 {"w", 30.5},
1462 {"uom", "cm"},
1463 }},
1464 {"status", "A"},
1465 },
1466 }
1467
1468 result, err := coll.InsertMany(context.TODO(), docs)
1469
1470
1471
1472 assert.NoError(t, err)
1473 assert.Len(t, result.InsertedIDs, 10)
1474 }
1475
1476 {
1477
1478
1479 result, err := coll.UpdateOne(
1480 context.TODO(),
1481 bson.D{
1482 {"item", "paper"},
1483 },
1484 bson.D{
1485 {"$set", bson.D{
1486 {"size.uom", "cm"},
1487 {"status", "P"},
1488 }},
1489 {"$currentDate", bson.D{
1490 {"lastModified", true},
1491 }},
1492 },
1493 )
1494
1495
1496
1497 assert.NoError(t, err)
1498 assert.Equal(t, int64(1), result.MatchedCount)
1499 assert.Equal(t, int64(1), result.ModifiedCount)
1500
1501 cursor, err := coll.Find(
1502 context.Background(),
1503 bson.D{
1504 {"item", "paper"},
1505 })
1506
1507 assert.NoError(t, err)
1508
1509 for cursor.Next(context.Background()) {
1510 doc := cursor.Current
1511
1512 uom, err := doc.LookupErr("size", "uom")
1513 assert.NoError(t, err)
1514 assert.Equal(t, uom.StringValue(), "cm")
1515
1516 status, err := doc.LookupErr("status")
1517 assert.NoError(t, err)
1518 assert.Equal(t, status.StringValue(), "P")
1519
1520 assert.True(t, containsKey(doc, "lastModified"))
1521 }
1522
1523 assert.NoError(t, cursor.Err())
1524 }
1525
1526 {
1527
1528
1529 result, err := coll.UpdateMany(
1530 context.TODO(),
1531 bson.D{
1532 {"qty", bson.D{
1533 {"$lt", 50},
1534 }},
1535 },
1536 bson.D{
1537 {"$set", bson.D{
1538 {"size.uom", "cm"},
1539 {"status", "P"},
1540 }},
1541 {"$currentDate", bson.D{
1542 {"lastModified", true},
1543 }},
1544 },
1545 )
1546
1547
1548
1549 assert.NoError(t, err)
1550 assert.Equal(t, int64(3), result.MatchedCount)
1551 assert.Equal(t, int64(3), result.ModifiedCount)
1552
1553 cursor, err := coll.Find(
1554 context.Background(),
1555 bson.D{
1556 {"qty", bson.D{
1557 {"$lt", 50},
1558 }},
1559 })
1560
1561 assert.NoError(t, err)
1562
1563 for cursor.Next(context.Background()) {
1564 doc := cursor.Current
1565
1566 uom, err := doc.LookupErr("size", "uom")
1567 assert.NoError(t, err)
1568 assert.Equal(t, uom.StringValue(), "cm")
1569
1570 status, err := doc.LookupErr("status")
1571 assert.NoError(t, err)
1572 assert.Equal(t, status.StringValue(), "P")
1573
1574 assert.True(t, containsKey(doc, "lastModified"))
1575 }
1576
1577 assert.NoError(t, cursor.Err())
1578 }
1579
1580 {
1581
1582
1583 result, err := coll.ReplaceOne(
1584 context.TODO(),
1585 bson.D{
1586 {"item", "paper"},
1587 },
1588 bson.D{
1589 {"item", "paper"},
1590 {"instock", bson.A{
1591 bson.D{
1592 {"warehouse", "A"},
1593 {"qty", 60},
1594 },
1595 bson.D{
1596 {"warehouse", "B"},
1597 {"qty", 40},
1598 },
1599 }},
1600 },
1601 )
1602
1603
1604
1605 assert.NoError(t, err)
1606 assert.Equal(t, int64(1), result.MatchedCount)
1607 assert.Equal(t, int64(1), result.ModifiedCount)
1608
1609 cursor, err := coll.Find(
1610 context.Background(),
1611 bson.D{
1612 {"item", "paper"},
1613 })
1614
1615 assert.NoError(t, err)
1616
1617 for cursor.Next(context.Background()) {
1618 assert.True(t, containsKey(cursor.Current, "_id"))
1619 assert.True(t, containsKey(cursor.Current, "item"))
1620 assert.True(t, containsKey(cursor.Current, "instock"))
1621
1622 instock, err := cursor.Current.LookupErr("instock")
1623 assert.NoError(t, err)
1624 vals, err := instock.Array().Values()
1625 assert.NoError(t, err)
1626 assert.Equal(t, len(vals), 2)
1627
1628 }
1629
1630 assert.NoError(t, cursor.Err())
1631 }
1632
1633 }
1634
1635
1636
1637 func DeleteExamples(t *testing.T, db *mongo.Database) {
1638 coll := db.Collection("inventory_delete")
1639
1640 err := coll.Drop(context.Background())
1641 assert.NoError(t, err)
1642
1643 {
1644
1645 docs := []interface{}{
1646 bson.D{
1647 {"item", "journal"},
1648 {"qty", 25},
1649 {"size", bson.D{
1650 {"h", 14},
1651 {"w", 21},
1652 {"uom", "cm"},
1653 }},
1654 {"status", "A"},
1655 },
1656 bson.D{
1657 {"item", "notebook"},
1658 {"qty", 50},
1659 {"size", bson.D{
1660 {"h", 8.5},
1661 {"w", 11},
1662 {"uom", "in"},
1663 }},
1664 {"status", "P"},
1665 },
1666 bson.D{
1667 {"item", "paper"},
1668 {"qty", 100},
1669 {"size", bson.D{
1670 {"h", 8.5},
1671 {"w", 11},
1672 {"uom", "in"},
1673 }},
1674 {"status", "D"},
1675 },
1676 bson.D{
1677 {"item", "planner"},
1678 {"qty", 75},
1679 {"size", bson.D{
1680 {"h", 22.85},
1681 {"w", 30},
1682 {"uom", "cm"},
1683 }},
1684 {"status", "D"},
1685 },
1686 bson.D{
1687 {"item", "postcard"},
1688 {"qty", 45},
1689 {"size", bson.D{
1690 {"h", 10},
1691 {"w", 15.25},
1692 {"uom", "cm"},
1693 }},
1694 {"status", "A"},
1695 },
1696 }
1697
1698 result, err := coll.InsertMany(context.TODO(), docs)
1699
1700
1701
1702 assert.NoError(t, err)
1703 assert.Len(t, result.InsertedIDs, 5)
1704 }
1705
1706 {
1707
1708
1709 result, err := coll.DeleteMany(
1710 context.TODO(),
1711 bson.D{
1712 {"status", "A"},
1713 },
1714 )
1715
1716
1717
1718 assert.NoError(t, err)
1719 assert.Equal(t, int64(2), result.DeletedCount)
1720 }
1721
1722 {
1723
1724
1725 result, err := coll.DeleteOne(
1726 context.TODO(),
1727 bson.D{
1728 {"status", "D"},
1729 },
1730 )
1731
1732
1733
1734 assert.NoError(t, err)
1735 assert.Equal(t, int64(1), result.DeletedCount)
1736
1737 }
1738
1739 {
1740
1741
1742 result, err := coll.DeleteMany(context.TODO(), bson.D{})
1743
1744
1745
1746 assert.NoError(t, err)
1747 assert.Equal(t, int64(2), result.DeletedCount)
1748 }
1749 }
1750
1751 var log = logger.New(ioutil.Discard, "", logger.LstdFlags)
1752
1753
1754
1755
1756
1757
1758 func UpdateEmployeeInfo(ctx context.Context, client *mongo.Client) error {
1759 employees := client.Database("hr").Collection("employees")
1760 events := client.Database("reporting").Collection("events")
1761
1762 return client.UseSession(ctx, func(sctx mongo.SessionContext) error {
1763 err := sctx.StartTransaction(options.Transaction().
1764 SetReadConcern(readconcern.Snapshot()).
1765 SetWriteConcern(writeconcern.New(writeconcern.WMajority())),
1766 )
1767 if err != nil {
1768 return err
1769 }
1770
1771 _, err = employees.UpdateOne(sctx, bson.D{{"employee", 3}}, bson.D{{"$set", bson.D{{"status", "Inactive"}}}})
1772 if err != nil {
1773 sctx.AbortTransaction(sctx)
1774 log.Println("caught exception during transaction, aborting.")
1775 return err
1776 }
1777 _, err = events.InsertOne(sctx, bson.D{{"employee", 3}, {"status", bson.D{{"new", "Inactive"}, {"old", "Active"}}}})
1778 if err != nil {
1779 sctx.AbortTransaction(sctx)
1780 log.Println("caught exception during transaction, aborting.")
1781 return err
1782 }
1783
1784 for {
1785 err = sctx.CommitTransaction(sctx)
1786 switch e := err.(type) {
1787 case nil:
1788 return nil
1789 case mongo.CommandError:
1790 if e.HasErrorLabel("UnknownTransactionCommitResult") {
1791 log.Println("UnknownTransactionCommitResult, retrying commit operation...")
1792 continue
1793 }
1794 log.Println("Error during commit...")
1795 return e
1796 default:
1797 log.Println("Error during commit...")
1798 return e
1799 }
1800 }
1801 })
1802 }
1803
1804
1805
1806
1807
1808
1809 func RunTransactionWithRetry(sctx mongo.SessionContext, txnFn func(mongo.SessionContext) error) error {
1810 for {
1811 err := txnFn(sctx)
1812 if err == nil {
1813 return nil
1814 }
1815
1816 log.Println("Transaction aborted. Caught exception during transaction.")
1817
1818
1819 if cmdErr, ok := err.(mongo.CommandError); ok && cmdErr.HasErrorLabel("TransientTransactionError") {
1820 log.Println("TransientTransactionError, retrying transaction...")
1821 continue
1822 }
1823 return err
1824 }
1825 }
1826
1827
1828
1829
1830
1831
1832 func CommitWithRetry(sctx mongo.SessionContext) error {
1833 for {
1834 err := sctx.CommitTransaction(sctx)
1835 switch e := err.(type) {
1836 case nil:
1837 log.Println("Transaction committed.")
1838 return nil
1839 case mongo.CommandError:
1840
1841 if e.HasErrorLabel("UnknownTransactionCommitResult") {
1842 log.Println("UnknownTransactionCommitResult, retrying commit operation...")
1843 continue
1844 }
1845 log.Println("Error during commit...")
1846 return e
1847 default:
1848 log.Println("Error during commit...")
1849 return e
1850 }
1851 }
1852 }
1853
1854
1855
1856
1857 func TransactionsExamples(ctx context.Context, client *mongo.Client) error {
1858 _, err := client.Database("hr").Collection("employees").InsertOne(ctx, bson.D{{"pi", 3.14159}})
1859 if err != nil {
1860 return err
1861 }
1862 _, err = client.Database("hr").Collection("employees").DeleteOne(ctx, bson.D{{"pi", 3.14159}})
1863 if err != nil {
1864 return err
1865 }
1866 _, err = client.Database("reporting").Collection("events").InsertOne(ctx, bson.D{{"pi", 3.14159}})
1867 if err != nil {
1868 return err
1869 }
1870 _, err = client.Database("reporting").Collection("events").DeleteOne(ctx, bson.D{{"pi", 3.14159}})
1871 if err != nil {
1872 return err
1873 }
1874
1875
1876 runTransactionWithRetry := func(sctx mongo.SessionContext, txnFn func(mongo.SessionContext) error) error {
1877 for {
1878 err := txnFn(sctx)
1879 if err == nil {
1880 return nil
1881 }
1882
1883 log.Println("Transaction aborted. Caught exception during transaction.")
1884
1885
1886 if cmdErr, ok := err.(mongo.CommandError); ok && cmdErr.HasErrorLabel("TransientTransactionError") {
1887 log.Println("TransientTransactionError, retrying transaction...")
1888 continue
1889 }
1890 return err
1891 }
1892 }
1893
1894 commitWithRetry := func(sctx mongo.SessionContext) error {
1895 for {
1896 err := sctx.CommitTransaction(sctx)
1897 switch e := err.(type) {
1898 case nil:
1899 log.Println("Transaction committed.")
1900 return nil
1901 case mongo.CommandError:
1902
1903 if e.HasErrorLabel("UnknownTransactionCommitResult") {
1904 log.Println("UnknownTransactionCommitResult, retrying commit operation...")
1905 continue
1906 }
1907 log.Println("Error during commit...")
1908 return e
1909 default:
1910 log.Println("Error during commit...")
1911 return e
1912 }
1913 }
1914 }
1915
1916
1917 updateEmployeeInfo := func(sctx mongo.SessionContext) error {
1918 employees := client.Database("hr").Collection("employees")
1919 events := client.Database("reporting").Collection("events")
1920
1921 err := sctx.StartTransaction(options.Transaction().
1922 SetReadConcern(readconcern.Snapshot()).
1923 SetWriteConcern(writeconcern.New(writeconcern.WMajority())),
1924 )
1925 if err != nil {
1926 return err
1927 }
1928
1929 _, err = employees.UpdateOne(sctx, bson.D{{"employee", 3}}, bson.D{{"$set", bson.D{{"status", "Inactive"}}}})
1930 if err != nil {
1931 sctx.AbortTransaction(sctx)
1932 log.Println("caught exception during transaction, aborting.")
1933 return err
1934 }
1935 _, err = events.InsertOne(sctx, bson.D{{"employee", 3}, {"status", bson.D{{"new", "Inactive"}, {"old", "Active"}}}})
1936 if err != nil {
1937 sctx.AbortTransaction(sctx)
1938 log.Println("caught exception during transaction, aborting.")
1939 return err
1940 }
1941
1942 return commitWithRetry(sctx)
1943 }
1944
1945 return client.UseSessionWithOptions(
1946 ctx, options.Session().SetDefaultReadPreference(readpref.Primary()),
1947 func(sctx mongo.SessionContext) error {
1948 return runTransactionWithRetry(sctx, updateEmployeeInfo)
1949 },
1950 )
1951 }
1952
1953
1954
1955
1956
1957
1958 func WithTransactionExample(ctx context.Context) error {
1959
1960
1961
1962
1963 uri := mtest.ClusterURI()
1964
1965 clientOpts := options.Client().ApplyURI(uri)
1966 client, err := mongo.Connect(ctx, clientOpts)
1967 if err != nil {
1968 return err
1969 }
1970 defer func() { _ = client.Disconnect(ctx) }()
1971
1972
1973 wcMajority := writeconcern.New(writeconcern.WMajority(), writeconcern.WTimeout(1*time.Second))
1974 wcMajorityCollectionOpts := options.Collection().SetWriteConcern(wcMajority)
1975 fooColl := client.Database("mydb1").Collection("foo", wcMajorityCollectionOpts)
1976 barColl := client.Database("mydb1").Collection("bar", wcMajorityCollectionOpts)
1977
1978
1979 callback := func(sessCtx mongo.SessionContext) (interface{}, error) {
1980
1981
1982 if _, err := fooColl.InsertOne(sessCtx, bson.D{{"abc", 1}}); err != nil {
1983 return nil, err
1984 }
1985 if _, err := barColl.InsertOne(sessCtx, bson.D{{"xyz", 999}}); err != nil {
1986 return nil, err
1987 }
1988
1989 return nil, nil
1990 }
1991
1992
1993 session, err := client.StartSession()
1994 if err != nil {
1995 return err
1996 }
1997 defer session.EndSession(ctx)
1998
1999 result, err := session.WithTransaction(ctx, callback)
2000 if err != nil {
2001 return err
2002 }
2003 log.Printf("result: %v\n", result)
2004 return nil
2005 }
2006
2007
2008
2009
2010
2011 func ChangeStreamExamples(t *testing.T, db *mongo.Database) {
2012 ctx := context.Background()
2013
2014 coll := db.Collection("inventory_changestream")
2015
2016 err := coll.Drop(context.Background())
2017 assert.NoError(t, err)
2018
2019 _, err = coll.InsertOne(ctx, bson.D{{"x", int32(1)}})
2020 assert.NoError(t, err)
2021
2022 var stop int32
2023
2024 doInserts := func(coll *mongo.Collection) {
2025 for atomic.LoadInt32(&stop) == 0 {
2026 _, err = coll.InsertOne(ctx, bson.D{{"x", 1}})
2027 time.Sleep(10 * time.Millisecond)
2028 coll.DeleteOne(ctx, bson.D{{"x", 1}})
2029 }
2030 }
2031
2032 go doInserts(coll)
2033
2034 {
2035
2036
2037 cs, err := coll.Watch(ctx, mongo.Pipeline{})
2038 assert.NoError(t, err)
2039 defer cs.Close(ctx)
2040
2041 ok := cs.Next(ctx)
2042 next := cs.Current
2043
2044
2045
2046 assert.True(t, ok)
2047 assert.NoError(t, err)
2048 assert.NotEqual(t, len(next), 0)
2049 }
2050 {
2051
2052
2053 cs, err := coll.Watch(ctx, mongo.Pipeline{}, options.ChangeStream().SetFullDocument(options.UpdateLookup))
2054 assert.NoError(t, err)
2055 defer cs.Close(ctx)
2056
2057 ok := cs.Next(ctx)
2058 next := cs.Current
2059
2060
2061
2062 assert.True(t, ok)
2063 assert.NoError(t, err)
2064 assert.NotEqual(t, len(next), 0)
2065 }
2066
2067 {
2068 original, err := coll.Watch(ctx, mongo.Pipeline{})
2069 assert.NoError(t, err)
2070 defer original.Close(ctx)
2071
2072 ok := original.Next(ctx)
2073 assert.True(t, ok)
2074
2075
2076 resumeToken := original.ResumeToken()
2077
2078 cs, err := coll.Watch(ctx, mongo.Pipeline{}, options.ChangeStream().SetResumeAfter(resumeToken))
2079 assert.NoError(t, err)
2080 defer cs.Close(ctx)
2081
2082 ok = cs.Next(ctx)
2083 result := cs.Current
2084
2085
2086
2087 assert.True(t, ok)
2088 assert.NoError(t, err)
2089 assert.NotEqual(t, len(result), 0)
2090 }
2091
2092 {
2093
2094 pipeline := mongo.Pipeline{bson.D{{"$match", bson.D{{"$or",
2095 bson.A{
2096 bson.D{{"fullDocument.username", "alice"}},
2097 bson.D{{"operationType", "delete"}}}}},
2098 }}}
2099 cs, err := coll.Watch(ctx, pipeline)
2100 assert.NoError(t, err)
2101 defer cs.Close(ctx)
2102
2103 ok := cs.Next(ctx)
2104 next := cs.Current
2105
2106
2107
2108 assert.True(t, ok)
2109 assert.NoError(t, err)
2110 assert.NotEqual(t, len(next), 0)
2111 }
2112
2113 atomic.StoreInt32(&stop, 1)
2114 }
2115
2116
2117
2118 func AggregationExamples(t *testing.T, db *mongo.Database) {
2119 ctx := context.Background()
2120
2121 salesColl := db.Collection("sales")
2122 airlinesColl := db.Collection("airlines")
2123 airAlliancesColl := db.Collection("air_alliances")
2124
2125 err := salesColl.Drop(ctx)
2126 assert.NoError(t, err)
2127 err = airlinesColl.Drop(ctx)
2128 assert.NoError(t, err)
2129 err = airAlliancesColl.Drop(ctx)
2130 assert.NoError(t, err)
2131
2132 date20180208 := parseDate(t, "2018-02-08T09:00:00.000Z")
2133 date20180109 := parseDate(t, "2018-01-09T07:12:00.000Z")
2134 date20180127 := parseDate(t, "2018-01-27T09:13:00.000Z")
2135 date20180203 := parseDate(t, "2018-02-03T07:58:00.000Z")
2136 date20180205 := parseDate(t, "2018-02-05T06:03:00.000Z")
2137 date20180111 := parseDate(t, "2018-01-11T07:15:00.000Z")
2138
2139 sales := []interface{}{
2140 bson.D{
2141 {"date", date20180208},
2142 {"items", bson.A{
2143 bson.D{
2144 {"fruit", "kiwi"},
2145 {"quantity", 2},
2146 {"price", 0.5},
2147 },
2148 bson.D{
2149 {"fruit", "apple"},
2150 {"quantity", 1},
2151 {"price", 1.0},
2152 },
2153 }},
2154 },
2155 bson.D{
2156 {"date", date20180109},
2157 {"items", bson.A{
2158 bson.D{
2159 {"fruit", "banana"},
2160 {"quantity", 8},
2161 {"price", 1.0},
2162 },
2163 bson.D{
2164 {"fruit", "apple"},
2165 {"quantity", 1},
2166 {"price", 1.0},
2167 },
2168 bson.D{
2169 {"fruit", "papaya"},
2170 {"quantity", 1},
2171 {"price", 4.0},
2172 },
2173 }},
2174 },
2175 bson.D{
2176 {"date", date20180127},
2177 {"items", bson.A{
2178 bson.D{
2179 {"fruit", "banana"},
2180 {"quantity", 1},
2181 {"price", 1.0},
2182 },
2183 }},
2184 },
2185 bson.D{
2186 {"date", date20180203},
2187 {"items", bson.A{
2188 bson.D{
2189 {"fruit", "banana"},
2190 {"quantity", 1},
2191 {"price", 1.0},
2192 },
2193 }},
2194 },
2195 bson.D{
2196 {"date", date20180205},
2197 {"items", bson.A{
2198 bson.D{
2199 {"fruit", "banana"},
2200 {"quantity", 1},
2201 {"price", 1.0},
2202 },
2203 bson.D{
2204 {"fruit", "mango"},
2205 {"quantity", 2},
2206 {"price", 2.0},
2207 },
2208 bson.D{
2209 {"fruit", "apple"},
2210 {"quantity", 1},
2211 {"price", 1.0},
2212 },
2213 }},
2214 },
2215 bson.D{
2216 {"date", date20180111},
2217 {"items", bson.A{
2218 bson.D{
2219 {"fruit", "banana"},
2220 {"quantity", 1},
2221 {"price", 1.0},
2222 },
2223 bson.D{
2224 {"fruit", "apple"},
2225 {"quantity", 1},
2226 {"price", 1.0},
2227 },
2228 bson.D{
2229 {"fruit", "papaya"},
2230 {"quantity", 3},
2231 {"price", 4.0},
2232 },
2233 }},
2234 },
2235 }
2236 airlines := []interface{}{
2237 bson.D{
2238 {"airline", 17},
2239 {"name", "Air Canada"},
2240 {"alias", "AC"},
2241 {"iata", "ACA"},
2242 {"icao", "AIR CANADA"},
2243 {"active", "Y"},
2244 {"country", "Canada"},
2245 {"base", "TAL"},
2246 },
2247 bson.D{
2248 {"airline", 18},
2249 {"name", "Turkish Airlines"},
2250 {"alias", "YK"},
2251 {"iata", "TRK"},
2252 {"icao", "TURKISH"},
2253 {"active", "Y"},
2254 {"country", "Turkey"},
2255 {"base", "AET"},
2256 },
2257 bson.D{
2258 {"airline", 22},
2259 {"name", "Saudia"},
2260 {"alias", "SV"},
2261 {"iata", "SVA"},
2262 {"icao", "SAUDIA"},
2263 {"active", "Y"},
2264 {"country", "Saudi Arabia"},
2265 {"base", "JSU"},
2266 },
2267 bson.D{
2268 {"airline", 29},
2269 {"name", "Finnair"},
2270 {"alias", "AY"},
2271 {"iata", "FIN"},
2272 {"icao", "FINNAIR"},
2273 {"active", "Y"},
2274 {"country", "Finland"},
2275 {"base", "JMZ"},
2276 },
2277 bson.D{
2278 {"airline", 34},
2279 {"name", "Afric'air Express"},
2280 {"alias", ""},
2281 {"iata", "AAX"},
2282 {"icao", "AFREX"},
2283 {"active", "N"},
2284 {"country", "Ivory Coast"},
2285 {"base", "LOK"},
2286 },
2287 bson.D{
2288 {"airline", 37},
2289 {"name", "Artem-Avia"},
2290 {"alias", ""},
2291 {"iata", "ABA"},
2292 {"icao", "ARTEM-AVIA"},
2293 {"active", "N"},
2294 {"country", "Ukraine"},
2295 {"base", "JBR"},
2296 },
2297 bson.D{
2298 {"airline", 38},
2299 {"name", "Lufthansa"},
2300 {"alias", "LH"},
2301 {"iata", "DLH"},
2302 {"icao", "LUFTHANSA"},
2303 {"active", "Y"},
2304 {"country", "Germany"},
2305 {"base", "CYS"},
2306 },
2307 }
2308 airAlliances := []interface{}{
2309 bson.D{
2310 {"name", "Star Alliance"},
2311 {"airlines", bson.A{
2312 "Air Canada",
2313 "Avianca",
2314 "Air China",
2315 "Air New Zealand",
2316 "Asiana Airlines",
2317 "Brussels Airlines",
2318 "Copa Airlines",
2319 "Croatia Airlines",
2320 "EgyptAir",
2321 "TAP Portugal",
2322 "United Airlines",
2323 "Turkish Airlines",
2324 "Swiss International Air Lines",
2325 "Lufthansa",
2326 }},
2327 },
2328 bson.D{
2329 {"name", "SkyTeam"},
2330 {"airlines", bson.A{
2331 "Aerolinias Argentinas",
2332 "Aeromexico",
2333 "Air Europa",
2334 "Air France",
2335 "Alitalia",
2336 "Delta Air Lines",
2337 "Garuda Indonesia",
2338 "Kenya Airways",
2339 "KLM",
2340 "Korean Air",
2341 "Middle East Airlines",
2342 "Saudia",
2343 }},
2344 },
2345 bson.D{
2346 {"name", "OneWorld"},
2347 {"airlines", bson.A{
2348 "Air Berlin",
2349 "American Airlines",
2350 "British Airways",
2351 "Cathay Pacific",
2352 "Finnair",
2353 "Iberia Airlines",
2354 "Japan Airlines",
2355 "LATAM Chile",
2356 "LATAM Brasil",
2357 "Malasya Airlines",
2358 "Canadian Airlines",
2359 }},
2360 },
2361 }
2362
2363 salesResult, salesErr := salesColl.InsertMany(ctx, sales)
2364 airlinesResult, airlinesErr := airlinesColl.InsertMany(ctx, airlines)
2365 airAlliancesResult, airAlliancesErr := airAlliancesColl.InsertMany(ctx, airAlliances)
2366
2367 assert.NoError(t, salesErr)
2368 assert.Len(t, salesResult.InsertedIDs, 6)
2369 assert.NoError(t, airlinesErr)
2370 assert.Len(t, airlinesResult.InsertedIDs, 7)
2371 assert.NoError(t, airAlliancesErr)
2372 assert.Len(t, airAlliancesResult.InsertedIDs, 3)
2373
2374 {
2375
2376 pipeline := mongo.Pipeline{
2377 {
2378 {"$match", bson.D{
2379 {"items.fruit", "banana"},
2380 }},
2381 },
2382 {
2383 {"$sort", bson.D{
2384 {"date", 1},
2385 }},
2386 },
2387 }
2388
2389 cursor, err := salesColl.Aggregate(ctx, pipeline)
2390
2391
2392
2393 assert.NoError(t, err)
2394 defer cursor.Close(ctx)
2395 requireCursorLength(t, cursor, 5)
2396 }
2397 {
2398
2399 pipeline := mongo.Pipeline{
2400 {
2401 {"$unwind", "$items"},
2402 },
2403 {
2404 {"$match", bson.D{
2405 {"items.fruit", "banana"},
2406 }},
2407 },
2408 {
2409 {"$group", bson.D{
2410 {"_id", bson.D{
2411 {"day", bson.D{
2412 {"$dayOfWeek", "$date"},
2413 }},
2414 }},
2415 {"count", bson.D{
2416 {"$sum", "$items.quantity"},
2417 }},
2418 }},
2419 },
2420 {
2421 {"$project", bson.D{
2422 {"dayOfWeek", "$_id.day"},
2423 {"numberSold", "$count"},
2424 {"_id", 0},
2425 }},
2426 },
2427 {
2428 {"$sort", bson.D{
2429 {"numberSold", 1},
2430 }},
2431 },
2432 }
2433
2434 cursor, err := salesColl.Aggregate(ctx, pipeline)
2435
2436
2437
2438 assert.NoError(t, err)
2439 defer cursor.Close(ctx)
2440 requireCursorLength(t, cursor, 4)
2441 }
2442 {
2443
2444 pipeline := mongo.Pipeline{
2445 {
2446 {"$unwind", "$items"},
2447 },
2448 {
2449 {"$group", bson.D{
2450 {"_id", bson.D{
2451 {"day", bson.D{
2452 {"$dayOfWeek", "$date"},
2453 }},
2454 }},
2455 {"items_sold", bson.D{
2456 {"$sum", "$items.quantity"},
2457 }},
2458 {"revenue", bson.D{
2459 {"$sum", bson.D{
2460 {"$multiply", bson.A{"$items.quantity", "$items.price"}},
2461 }},
2462 }},
2463 }},
2464 },
2465 {
2466 {"$project", bson.D{
2467 {"day", "$_id.day"},
2468 {"revenue", 1},
2469 {"items_sold", 1},
2470 {"discount", bson.D{
2471 {"$cond", bson.D{
2472 {"if", bson.D{
2473 {"$lte", bson.A{"$revenue", 250}},
2474 }},
2475 {"then", 25},
2476 {"else", 0},
2477 }},
2478 }},
2479 }},
2480 },
2481 }
2482
2483 cursor, err := salesColl.Aggregate(ctx, pipeline)
2484
2485
2486
2487 assert.NoError(t, err)
2488 defer cursor.Close(ctx)
2489 requireCursorLength(t, cursor, 4)
2490 }
2491 {
2492
2493 pipeline := mongo.Pipeline{
2494 {
2495 {"$lookup", bson.D{
2496 {"from", "air_airlines"},
2497 {"let", bson.D{
2498 {"constituents", "$airlines"}},
2499 },
2500 {"pipeline", bson.A{bson.D{
2501 {"$match", bson.D{
2502 {"$expr", bson.D{
2503 {"$in", bson.A{"$name", "$$constituents"}},
2504 }},
2505 }},
2506 }}},
2507 {"as", "airlines"},
2508 }},
2509 },
2510 {
2511 {"$project", bson.D{
2512 {"_id", 0},
2513 {"name", 1},
2514 {"airlines", bson.D{
2515 {"$filter", bson.D{
2516 {"input", "$airlines"},
2517 {"as", "airline"},
2518 {"cond", bson.D{
2519 {"$eq", bson.A{"$$airline.country", "Canada"}},
2520 }},
2521 }},
2522 }},
2523 }},
2524 },
2525 }
2526
2527 cursor, err := airAlliancesColl.Aggregate(ctx, pipeline)
2528
2529
2530
2531 assert.NoError(t, err)
2532 defer cursor.Close(ctx)
2533 requireCursorLength(t, cursor, 3)
2534 }
2535 }
2536
2537
2538
2539 func CausalConsistencyExamples(client *mongo.Client) error {
2540 ctx := context.Background()
2541 coll := client.Database("test").Collection("items")
2542
2543 currentDate := time.Now()
2544
2545 err := coll.Drop(ctx)
2546 if err != nil {
2547 return err
2548 }
2549
2550
2551
2552
2553 opts := options.Session().SetDefaultReadConcern(readconcern.Majority()).SetDefaultWriteConcern(
2554 writeconcern.New(writeconcern.WMajority(), writeconcern.WTimeout(1000)))
2555 session1, err := client.StartSession(opts)
2556 if err != nil {
2557 return err
2558 }
2559 defer session1.EndSession(context.TODO())
2560
2561 err = client.UseSessionWithOptions(context.TODO(), opts, func(sctx mongo.SessionContext) error {
2562
2563 _, err = coll.UpdateOne(sctx, bson.D{{"sku", 111}}, bson.D{{"$set", bson.D{{"end", currentDate}}}})
2564 if err != nil {
2565 return err
2566 }
2567
2568
2569 _, err = coll.InsertOne(sctx, bson.D{{"sku", "nuts-111"}, {"name", "Pecans"}, {"start", currentDate}})
2570 if err != nil {
2571 return err
2572 }
2573
2574 return nil
2575 })
2576
2577 if err != nil {
2578 return err
2579 }
2580
2581
2582
2583
2584
2585
2586 opts = options.Session().SetDefaultReadPreference(readpref.Secondary()).SetDefaultReadConcern(
2587 readconcern.Majority()).SetDefaultWriteConcern(writeconcern.New(writeconcern.WMajority(),
2588 writeconcern.WTimeout(1000)))
2589 session2, err := client.StartSession(opts)
2590 if err != nil {
2591 return err
2592 }
2593 defer session2.EndSession(context.TODO())
2594
2595 err = client.UseSessionWithOptions(context.TODO(), opts, func(sctx mongo.SessionContext) error {
2596
2597 clusterTime := session1.ClusterTime()
2598 session2.AdvanceClusterTime(clusterTime)
2599
2600
2601 operationTime := session1.OperationTime()
2602 session2.AdvanceOperationTime(operationTime)
2603
2604 cursor, err := coll.Find(sctx, bson.D{{"end", nil}})
2605
2606 if err != nil {
2607 return err
2608 }
2609
2610 for cursor.Next(sctx) {
2611 doc := cursor.Current
2612 fmt.Printf("Document: %v\n", doc.String())
2613 }
2614
2615 return cursor.Err()
2616 })
2617
2618 if err != nil {
2619 return err
2620 }
2621
2622
2623 return nil
2624 }
2625
2626
2627
2628 func RunCommandExamples(t *testing.T, db *mongo.Database) {
2629 ctx := context.Background()
2630
2631 coll := db.Collection("restaurants")
2632
2633 err := coll.Drop(ctx)
2634 assert.NoError(t, err)
2635
2636 {
2637
2638 res := db.RunCommand(ctx, bson.D{{"buildInfo", 1}})
2639
2640
2641
2642 err := res.Err()
2643 assert.NoError(t, err)
2644 }
2645 }
2646
2647
2648
2649 func IndexExamples(t *testing.T, db *mongo.Database) {
2650 ctx := context.Background()
2651
2652 recordsColl := db.Collection("records")
2653 restaurantsColl := db.Collection("restaurants")
2654
2655 err := recordsColl.Drop(ctx)
2656 assert.NoError(t, err)
2657 err = restaurantsColl.Drop(ctx)
2658 assert.NoError(t, err)
2659
2660 records := []interface{}{
2661 bson.D{
2662 {"student", "Marty McFly"},
2663 {"classYear", 1986},
2664 {"school", "Hill Valley High"},
2665 {"score", 56.5},
2666 },
2667 bson.D{
2668 {"student", "Ferris F. Bueller"},
2669 {"classYear", 1987},
2670 {"school", "Glenbrook North High"},
2671 {"status", "Suspended"},
2672 {"score", 76.0},
2673 },
2674 bson.D{
2675 {"student", "Reynard Muldoon"},
2676 {"classYear", 2007},
2677 {"school", "Stonetown Middle"},
2678 {"score", 99.9},
2679 },
2680 }
2681 restaurants := []interface{}{
2682 bson.D{
2683 {"name", "Chez Panisse"},
2684 {"cuisine", "American/French"},
2685 {"city", "Oakland"},
2686 {"state", "California"},
2687 {"country", "United States"},
2688 {"rating", 4.9},
2689 },
2690 bson.D{
2691 {"name", "Central"},
2692 {"cuisine", "Peruvian"},
2693 {"city", "Lima"},
2694 {"country", "Peru"},
2695 {"rating", 5.8},
2696 },
2697 bson.D{
2698 {"name", "Eleven Madison Park"},
2699 {"cuisine", "French"},
2700 {"city", "New York City"},
2701 {"state", "New York"},
2702 {"country", "United States"},
2703 {"rating", 7.1},
2704 },
2705 bson.D{
2706 {"name", "Gaggan"},
2707 {"cuisine", "Thai Fusion"},
2708 {"city", "Bangkok"},
2709 {"country", "Thailand"},
2710 {"rating", 9.2},
2711 },
2712 bson.D{
2713 {"name", "Dad's Grill"},
2714 {"cuisine", "BBQ"},
2715 {"city", "Oklahoma City"},
2716 {"state", "Oklahoma"},
2717 {"country", "United States"},
2718 {"rating", 2.1},
2719 },
2720 }
2721
2722 recordsResult, recordsErr := recordsColl.InsertMany(ctx, records)
2723 restaurantsResult, restaurantsErr := restaurantsColl.InsertMany(ctx, restaurants)
2724
2725 assert.NoError(t, recordsErr)
2726 assert.Len(t, recordsResult.InsertedIDs, 3)
2727 assert.NoError(t, restaurantsErr)
2728 assert.Len(t, restaurantsResult.InsertedIDs, 5)
2729
2730 {
2731
2732 indexModel := mongo.IndexModel{
2733 Keys: bson.D{
2734 {"score", 1},
2735 },
2736 }
2737 _, err := recordsColl.Indexes().CreateOne(ctx, indexModel)
2738
2739
2740
2741 assert.NoError(t, err)
2742 }
2743 {
2744
2745 partialFilterExpression := bson.D{
2746 {"rating", bson.D{
2747 {"$gt", 5},
2748 }},
2749 }
2750 indexModel := mongo.IndexModel{
2751 Keys: bson.D{
2752 {"cuisine", 1},
2753 {"name", 1},
2754 },
2755 Options: options.Index().SetPartialFilterExpression(partialFilterExpression),
2756 }
2757
2758 _, err := restaurantsColl.Indexes().CreateOne(ctx, indexModel)
2759
2760
2761
2762 assert.NoError(t, err)
2763 }
2764 }
2765
2766
2767
2768
2769 func StableAPIExample() {
2770 ctx := context.TODO()
2771
2772
2773
2774
2775 uri := mtest.ClusterURI()
2776
2777 serverAPIOptions := options.ServerAPI(options.ServerAPIVersion1)
2778 clientOpts := options.Client().ApplyURI(uri).SetServerAPIOptions(serverAPIOptions)
2779 client, err := mongo.Connect(ctx, clientOpts)
2780 if err != nil {
2781 panic(err)
2782 }
2783 defer func() { _ = client.Disconnect(ctx) }()
2784 }
2785
2786
2787
2788
2789
2790
2791 func StableAPIStrictExample() {
2792 ctx := context.TODO()
2793
2794
2795
2796
2797 uri := mtest.ClusterURI()
2798
2799 serverAPIOptions := options.ServerAPI(options.ServerAPIVersion1).SetStrict(true)
2800 clientOpts := options.Client().ApplyURI(uri).SetServerAPIOptions(serverAPIOptions)
2801 client, err := mongo.Connect(ctx, clientOpts)
2802 if err != nil {
2803 panic(err)
2804 }
2805 defer func() { _ = client.Disconnect(ctx) }()
2806 }
2807
2808
2809
2810
2811
2812
2813 func StableAPINonStrictExample() {
2814 ctx := context.TODO()
2815
2816
2817
2818
2819 uri := mtest.ClusterURI()
2820
2821 serverAPIOptions := options.ServerAPI(options.ServerAPIVersion1).SetStrict(false)
2822 clientOpts := options.Client().ApplyURI(uri).SetServerAPIOptions(serverAPIOptions)
2823 client, err := mongo.Connect(ctx, clientOpts)
2824 if err != nil {
2825 panic(err)
2826 }
2827 defer func() { _ = client.Disconnect(ctx) }()
2828 }
2829
2830
2831
2832
2833
2834
2835
2836 func StableAPIDeprecationErrorsExample() {
2837 ctx := context.TODO()
2838
2839
2840
2841
2842 uri := mtest.ClusterURI()
2843
2844 serverAPIOptions := options.ServerAPI(options.ServerAPIVersion1).SetDeprecationErrors(true)
2845 clientOpts := options.Client().ApplyURI(uri).SetServerAPIOptions(serverAPIOptions)
2846 client, err := mongo.Connect(ctx, clientOpts)
2847 if err != nil {
2848 panic(err)
2849 }
2850 defer func() { _ = client.Disconnect(ctx) }()
2851 }
2852
2853
2854
2855
2856
2857 func StableAPIStrictCountExample(t *testing.T) {
2858
2859
2860
2861
2862 uri := mtest.ClusterURI()
2863
2864 serverAPIOptions := options.ServerAPI(options.ServerAPIVersion1).SetStrict(true)
2865 clientOpts := options.Client().ApplyURI(uri).SetServerAPIOptions(serverAPIOptions)
2866
2867 client, err := mongo.Connect(context.TODO(), clientOpts)
2868 assert.Nil(t, err, "Connect error: %v", err)
2869 defer func() { _ = client.Disconnect(context.TODO()) }()
2870
2871
2872
2873 coll := client.Database("db").Collection("sales")
2874 docs := []interface{}{
2875 bson.D{{"_id", 1}, {"item", "abc"}, {"price", 10}, {"quantity", 2}, {"date", "2021-01-01T08:00:00Z"}},
2876 bson.D{{"_id", 2}, {"item", "jkl"}, {"price", 20}, {"quantity", 1}, {"date", "2021-02-03T09:00:00Z"}},
2877 bson.D{{"_id", 3}, {"item", "xyz"}, {"price", 5}, {"quantity", 5}, {"date", "2021-02-03T09:05:00Z"}},
2878 bson.D{{"_id", 4}, {"item", "abc"}, {"price", 10}, {"quantity", 10}, {"date", "2021-02-15T08:00:00Z"}},
2879 bson.D{{"_id", 5}, {"item", "xyz"}, {"price", 5}, {"quantity", 10}, {"date", "2021-02-15T09:05:00Z"}},
2880 bson.D{{"_id", 6}, {"item", "xyz"}, {"price", 5}, {"quantity", 5}, {"date", "2021-02-15T12:05:10Z"}},
2881 bson.D{{"_id", 7}, {"item", "xyz"}, {"price", 5}, {"quantity", 10}, {"date", "2021-02-15T14:12:12Z"}},
2882 bson.D{{"_id", 8}, {"item", "abc"}, {"price", 10}, {"quantity", 5}, {"date", "2021-03-16T20:20:13Z"}},
2883 }
2884 _, err = coll.InsertMany(context.TODO(), docs)
2885
2886
2887 defer func() { _ = coll.Drop(context.TODO()) }()
2888 assert.Nil(t, err, "InsertMany error: %v", err)
2889
2890 res := client.Database("db").RunCommand(context.TODO(), bson.D{{"count", "sales"}})
2891 assert.NotNil(t, res.Err(), "expected RunCommand error, got nil")
2892 expectedErr := "Provided apiStrict:true, but the command count is not in API Version 1"
2893 assert.True(t, strings.Contains(res.Err().Error(), expectedErr),
2894 "expected RunCommand error to contain %q, got %q", expectedErr, res.Err().Error())
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904 count, err := coll.CountDocuments(context.TODO(), bson.D{})
2905
2906
2907 assert.Nil(t, err, "CountDocuments error: %v", err)
2908 assert.Equal(t, count, int64(8), "expected count to be 8, got %v", count)
2909
2910
2911
2912
2913
2914
2915 }
2916
2917
2918
2919 func StableAPIExamples() {
2920 StableAPIExample()
2921 StableAPIStrictExample()
2922 StableAPINonStrictExample()
2923 StableAPIDeprecationErrorsExample()
2924 }
2925
2926 func insertSnapshotQueryTestData(mt *mtest.T) {
2927 catColl := mt.CreateCollection(mtest.Collection{Name: "cats"}, true)
2928 _, err := catColl.InsertMany(context.Background(), []interface{}{
2929 bson.D{
2930 {"adoptable", false},
2931 {"name", "Miyagi"},
2932 {"color", "grey-white"},
2933 {"age", 14},
2934 },
2935 bson.D{
2936 {"adoptable", true},
2937 {"name", "Joyce"},
2938 {"color", "black"},
2939 {"age", 10},
2940 },
2941 })
2942 assert.NoError(mt, err)
2943
2944 dogColl := mt.CreateCollection(mtest.Collection{Name: "dogs"}, true)
2945 _, err = dogColl.InsertMany(context.Background(), []interface{}{
2946 bson.D{
2947 {"adoptable", true},
2948 {"name", "Cormac"},
2949 {"color", "rust"},
2950 {"age", 7},
2951 },
2952 bson.D{
2953 {"adoptable", true},
2954 {"name", "Frank"},
2955 {"color", "yellow"},
2956 {"age", 2},
2957 },
2958 })
2959 assert.NoError(mt, err)
2960
2961 salesColl := mt.CreateCollection(mtest.Collection{Name: "sales"}, true)
2962 _, err = salesColl.InsertMany(context.Background(), []interface{}{
2963 bson.D{
2964 {"shoeType", "hiking boot"},
2965 {"price", 30.0},
2966 {"saleDate", time.Now()},
2967 },
2968 })
2969 assert.NoError(mt, err)
2970 }
2971
2972 func snapshotQueryPetExample(mt *mtest.T) error {
2973 client := mt.Client
2974 db := mt.DB
2975
2976
2977 ctx := context.TODO()
2978
2979 sess, err := client.StartSession(options.Session().SetSnapshot(true))
2980 if err != nil {
2981 return err
2982 }
2983 defer sess.EndSession(ctx)
2984
2985 var adoptablePetsCount int32
2986 err = mongo.WithSession(ctx, sess, func(ctx mongo.SessionContext) error {
2987
2988 const adoptableCatsOutput = "adoptableCatsCount"
2989 cursor, err := db.Collection("cats").Aggregate(ctx, mongo.Pipeline{
2990 bson.D{{"$match", bson.D{{"adoptable", true}}}},
2991 bson.D{{"$count", adoptableCatsOutput}},
2992 })
2993 if err != nil {
2994 return err
2995 }
2996 if !cursor.Next(ctx) {
2997 return fmt.Errorf("expected aggregate to return a document, but got none")
2998 }
2999
3000 resp := cursor.Current.Lookup(adoptableCatsOutput)
3001 adoptableCatsCount, ok := resp.Int32OK()
3002 if !ok {
3003 return fmt.Errorf("failed to find int32 field %q in document %v", adoptableCatsOutput, cursor.Current)
3004 }
3005 adoptablePetsCount += adoptableCatsCount
3006
3007
3008 const adoptableDogsOutput = "adoptableDogsCount"
3009 cursor, err = db.Collection("dogs").Aggregate(ctx, mongo.Pipeline{
3010 bson.D{{"$match", bson.D{{"adoptable", true}}}},
3011 bson.D{{"$count", adoptableDogsOutput}},
3012 })
3013 if err != nil {
3014 return err
3015 }
3016 if !cursor.Next(ctx) {
3017 return fmt.Errorf("expected aggregate to return a document, but got none")
3018 }
3019
3020 resp = cursor.Current.Lookup(adoptableDogsOutput)
3021 adoptableDogsCount, ok := resp.Int32OK()
3022 if !ok {
3023 return fmt.Errorf("failed to find int32 field %q in document %v", adoptableDogsOutput, cursor.Current)
3024 }
3025 adoptablePetsCount += adoptableDogsCount
3026 return nil
3027 })
3028 if err != nil {
3029 return err
3030 }
3031
3032 assert.Equal(mt, int32(3), adoptablePetsCount, "expected 3 total adoptable pets")
3033 return nil
3034 }
3035
3036 func snapshotQueryRetailExample(mt *mtest.T) error {
3037 client := mt.Client
3038 db := mt.DB
3039
3040
3041 ctx := context.TODO()
3042
3043 sess, err := client.StartSession(options.Session().SetSnapshot(true))
3044 if err != nil {
3045 return err
3046 }
3047 defer sess.EndSession(ctx)
3048
3049 var totalDailySales int32
3050 err = mongo.WithSession(ctx, sess, func(ctx mongo.SessionContext) error {
3051
3052 const totalDailySalesOutput = "totalDailySales"
3053 cursor, err := db.Collection("sales").Aggregate(ctx, mongo.Pipeline{
3054 bson.D{{"$match",
3055 bson.D{{"$expr",
3056 bson.D{{"$gt",
3057 bson.A{"$saleDate",
3058 bson.D{{"$dateSubtract",
3059 bson.D{
3060 {"startDate", "$$NOW"},
3061 {"unit", "day"},
3062 {"amount", 1},
3063 },
3064 }},
3065 },
3066 }},
3067 }},
3068 }},
3069 bson.D{{"$count", totalDailySalesOutput}},
3070 })
3071 if err != nil {
3072 return err
3073 }
3074 if !cursor.Next(ctx) {
3075 return fmt.Errorf("expected aggregate to return a document, but got none")
3076 }
3077
3078 resp := cursor.Current.Lookup(totalDailySalesOutput)
3079
3080 var ok bool
3081 totalDailySales, ok = resp.Int32OK()
3082 if !ok {
3083 return fmt.Errorf("failed to find int32 field %q in document %v", totalDailySalesOutput, cursor.Current)
3084 }
3085 return nil
3086 })
3087 if err != nil {
3088 return err
3089 }
3090
3091 assert.Equal(mt, int32(1), totalDailySales, "expected 1 total daily sale")
3092 return nil
3093 }
3094
3095
3096
3097 func SnapshotQueryExamples(mt *mtest.T) {
3098 insertSnapshotQueryTestData(mt)
3099 assert.NoError(mt, snapshotQueryPetExample(mt))
3100 assert.NoError(mt, snapshotQueryRetailExample(mt))
3101 }
3102
View as plain text