Skip to content

Commit 023a864

Browse files
GODRIVER-2310 Add snapshot query examples (#887)
1 parent 0cd9fa6 commit 023a864

File tree

2 files changed

+237
-21
lines changed

2 files changed

+237
-21
lines changed

examples/documentation_examples/examples.go

Lines changed: 177 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"go.mongodb.org/mongo-driver/bson"
2424
"go.mongodb.org/mongo-driver/bson/primitive"
2525
"go.mongodb.org/mongo-driver/mongo"
26+
"go.mongodb.org/mongo-driver/mongo/integration/mtest"
2627
"go.mongodb.org/mongo-driver/mongo/options"
2728
"go.mongodb.org/mongo-driver/mongo/readconcern"
2829
"go.mongodb.org/mongo-driver/mongo/readpref"
@@ -2894,7 +2895,7 @@ func StableAPIDeprecationErrorsExample() {
28942895
// StableAPIStrictCountExample is an example of using CountDocuments instead of a traditional count
28952896
// with a strict stable API since the count command does not belong to API version 1.
28962897
func StableAPIStrictCountExample(t *testing.T) {
2897-
uri := "mongodb://localhost:27017"
2898+
uri := mtest.ClusterURI()
28982899

28992900
serverAPIOptions := options.ServerAPI(options.ServerAPIVersion1).SetStrict(true)
29002901
clientOpts := options.Client().ApplyURI(uri).SetServerAPIOptions(serverAPIOptions)
@@ -2956,3 +2957,178 @@ func StableAPIExamples() {
29562957
StableAPINonStrictExample()
29572958
StableAPIDeprecationErrorsExample()
29582959
}
2960+
2961+
func insertSnapshotQueryTestData(mt *mtest.T) {
2962+
catColl := mt.CreateCollection(mtest.Collection{Name: "cats"}, true)
2963+
_, err := catColl.InsertMany(context.Background(), []interface{}{
2964+
bson.D{
2965+
{"adoptable", false},
2966+
{"name", "Miyagi"},
2967+
{"color", "grey-white"},
2968+
{"age", 14},
2969+
},
2970+
bson.D{
2971+
{"adoptable", true},
2972+
{"name", "Joyce"},
2973+
{"color", "black"},
2974+
{"age", 10},
2975+
},
2976+
})
2977+
require.NoError(mt, err)
2978+
2979+
dogColl := mt.CreateCollection(mtest.Collection{Name: "dogs"}, true)
2980+
_, err = dogColl.InsertMany(context.Background(), []interface{}{
2981+
bson.D{
2982+
{"adoptable", true},
2983+
{"name", "Cormac"},
2984+
{"color", "rust"},
2985+
{"age", 7},
2986+
},
2987+
bson.D{
2988+
{"adoptable", true},
2989+
{"name", "Frank"},
2990+
{"color", "yellow"},
2991+
{"age", 2},
2992+
},
2993+
})
2994+
require.NoError(mt, err)
2995+
2996+
salesColl := mt.CreateCollection(mtest.Collection{Name: "sales"}, true)
2997+
_, err = salesColl.InsertMany(context.Background(), []interface{}{
2998+
bson.D{
2999+
{"shoeType", "hiking boot"},
3000+
{"price", 30.0},
3001+
{"saleDate", time.Now()},
3002+
},
3003+
})
3004+
require.NoError(mt, err)
3005+
}
3006+
3007+
func snapshotQueryPetExample(mt *mtest.T) error {
3008+
client := mt.Client
3009+
db := mt.DB
3010+
3011+
// Start Snapshot Query Example 1
3012+
ctx := context.TODO()
3013+
3014+
sess, err := client.StartSession(options.Session().SetSnapshot(true))
3015+
if err != nil {
3016+
return err
3017+
}
3018+
defer sess.EndSession(ctx)
3019+
3020+
var adoptablePetsCount int32
3021+
err = mongo.WithSession(ctx, sess, func(ctx mongo.SessionContext) error {
3022+
// Count the adoptable cats
3023+
const adoptableCatsOutput = "adoptableCatsCount"
3024+
cursor, err := db.Collection("cats").Aggregate(ctx, mongo.Pipeline{
3025+
bson.D{{"$match", bson.D{{"adoptable", true}}}},
3026+
bson.D{{"$count", adoptableCatsOutput}},
3027+
})
3028+
if err != nil {
3029+
return err
3030+
}
3031+
if !cursor.Next(ctx) {
3032+
return fmt.Errorf("expected aggregate to return a document, but got none")
3033+
}
3034+
3035+
resp := cursor.Current.Lookup(adoptableCatsOutput)
3036+
adoptableCatsCount, ok := resp.Int32OK()
3037+
if !ok {
3038+
return fmt.Errorf("failed to find int32 field %q in document %v", adoptableCatsOutput, cursor.Current)
3039+
}
3040+
adoptablePetsCount += adoptableCatsCount
3041+
3042+
// Count the adoptable dogs
3043+
const adoptableDogsOutput = "adoptableDogsCount"
3044+
cursor, err = db.Collection("dogs").Aggregate(ctx, mongo.Pipeline{
3045+
bson.D{{"$match", bson.D{{"adoptable", true}}}},
3046+
bson.D{{"$count", adoptableDogsOutput}},
3047+
})
3048+
if err != nil {
3049+
return err
3050+
}
3051+
if !cursor.Next(ctx) {
3052+
return fmt.Errorf("expected aggregate to return a document, but got none")
3053+
}
3054+
3055+
resp = cursor.Current.Lookup(adoptableDogsOutput)
3056+
adoptableDogsCount, ok := resp.Int32OK()
3057+
if !ok {
3058+
return fmt.Errorf("failed to find int32 field %q in document %v", adoptableDogsOutput, cursor.Current)
3059+
}
3060+
adoptablePetsCount += adoptableDogsCount
3061+
return nil
3062+
})
3063+
if err != nil {
3064+
return err
3065+
}
3066+
// End Snapshot Query Example 1
3067+
require.Equal(mt, int32(3), adoptablePetsCount, "expected 3 total adoptable pets")
3068+
return nil
3069+
}
3070+
3071+
func snapshotQueryRetailExample(mt *mtest.T) error {
3072+
client := mt.Client
3073+
db := mt.DB
3074+
3075+
// Start Snapshot Query Example 2
3076+
ctx := context.TODO()
3077+
3078+
sess, err := client.StartSession(options.Session().SetSnapshot(true))
3079+
if err != nil {
3080+
return err
3081+
}
3082+
defer sess.EndSession(ctx)
3083+
3084+
var totalDailySales int32
3085+
err = mongo.WithSession(ctx, sess, func(ctx mongo.SessionContext) error {
3086+
// Count the total daily sales
3087+
const totalDailySalesOutput = "totalDailySales"
3088+
cursor, err := db.Collection("sales").Aggregate(ctx, mongo.Pipeline{
3089+
bson.D{{"$match",
3090+
bson.D{{"$expr",
3091+
bson.D{{"$gt",
3092+
bson.A{"$saleDate",
3093+
bson.D{{"$dateSubtract",
3094+
bson.D{
3095+
{"startDate", "$$NOW"},
3096+
{"unit", "day"},
3097+
{"amount", 1},
3098+
},
3099+
}},
3100+
},
3101+
}},
3102+
}},
3103+
}},
3104+
bson.D{{"$count", totalDailySalesOutput}},
3105+
})
3106+
if err != nil {
3107+
return err
3108+
}
3109+
if !cursor.Next(ctx) {
3110+
return fmt.Errorf("expected aggregate to return a document, but got none")
3111+
}
3112+
3113+
resp := cursor.Current.Lookup(totalDailySalesOutput)
3114+
3115+
var ok bool
3116+
totalDailySales, ok = resp.Int32OK()
3117+
if !ok {
3118+
return fmt.Errorf("failed to find int32 field %q in document %v", totalDailySalesOutput, cursor.Current)
3119+
}
3120+
return nil
3121+
})
3122+
if err != nil {
3123+
return err
3124+
}
3125+
// End Snapshot Query Example 2
3126+
require.Equal(mt, int32(1), totalDailySales, "expected 1 total daily sale")
3127+
return nil
3128+
}
3129+
3130+
func SnapshotQueryExamples(mt *mtest.T) {
3131+
insertSnapshotQueryTestData(mt)
3132+
require.NoError(mt, snapshotQueryPetExample(mt))
3133+
require.NoError(mt, snapshotQueryRetailExample(mt))
3134+
}

examples/documentation_examples/examples_test.go

Lines changed: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ package documentation_examples_test
1111

1212
import (
1313
"context"
14+
"log"
1415
"os"
1516
"testing"
1617
"time"
@@ -20,12 +21,23 @@ import (
2021
"go.mongodb.org/mongo-driver/internal/testutil"
2122
"go.mongodb.org/mongo-driver/mongo"
2223
"go.mongodb.org/mongo-driver/mongo/description"
24+
"go.mongodb.org/mongo-driver/mongo/integration/mtest"
2325
"go.mongodb.org/mongo-driver/mongo/options"
2426
"go.mongodb.org/mongo-driver/x/bsonx"
2527
"go.mongodb.org/mongo-driver/x/mongo/driver/connstring"
2628
"go.mongodb.org/mongo-driver/x/mongo/driver/topology"
2729
)
2830

31+
func TestMain(m *testing.M) {
32+
if err := mtest.Setup(); err != nil {
33+
log.Fatal(err)
34+
}
35+
defer os.Exit(m.Run())
36+
if err := mtest.Teardown(); err != nil {
37+
log.Fatal(err)
38+
}
39+
}
40+
2941
func TestDocumentationExamples(t *testing.T) {
3042
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
3143
defer cancel()
@@ -37,30 +49,58 @@ func TestDocumentationExamples(t *testing.T) {
3749

3850
db := client.Database("documentation_examples")
3951

40-
documentation_examples.InsertExamples(t, db)
41-
documentation_examples.QueryToplevelFieldsExamples(t, db)
42-
documentation_examples.QueryEmbeddedDocumentsExamples(t, db)
43-
documentation_examples.QueryArraysExamples(t, db)
44-
documentation_examples.QueryArrayEmbeddedDocumentsExamples(t, db)
45-
documentation_examples.QueryNullMissingFieldsExamples(t, db)
46-
documentation_examples.ProjectionExamples(t, db)
47-
documentation_examples.UpdateExamples(t, db)
48-
documentation_examples.DeleteExamples(t, db)
49-
documentation_examples.RunCommandExamples(t, db)
50-
documentation_examples.IndexExamples(t, db)
51-
documentation_examples.StableAPIExamples()
52+
t.Run("InsertExamples", func(t *testing.T) {
53+
documentation_examples.InsertExamples(t, db)
54+
})
55+
t.Run("QueryArraysExamples", func(t *testing.T) {
56+
documentation_examples.QueryArraysExamples(t, db)
57+
})
58+
t.Run("ProjectionExamples", func(t *testing.T) {
59+
documentation_examples.ProjectionExamples(t, db)
60+
})
61+
t.Run("UpdateExamples", func(t *testing.T) {
62+
documentation_examples.UpdateExamples(t, db)
63+
})
64+
t.Run("DeleteExamples", func(t *testing.T) {
65+
documentation_examples.DeleteExamples(t, db)
66+
})
67+
t.Run("RunCommandExamples", func(t *testing.T) {
68+
documentation_examples.RunCommandExamples(t, db)
69+
})
70+
t.Run("IndexExamples", func(t *testing.T) {
71+
documentation_examples.IndexExamples(t, db)
72+
})
73+
t.Run("StableAPExamples", func(t *testing.T) {
74+
documentation_examples.StableAPIExamples()
75+
})
76+
t.Run("QueryToplevelFieldsExamples", func(t *testing.T) {
77+
documentation_examples.QueryToplevelFieldsExamples(t, db)
78+
})
79+
t.Run("QueryEmbeddedDocumentsExamples", func(t *testing.T) {
80+
documentation_examples.QueryEmbeddedDocumentsExamples(t, db)
81+
})
82+
t.Run("QueryArrayEmbeddedDocumentsExamples", func(t *testing.T) {
83+
documentation_examples.QueryArrayEmbeddedDocumentsExamples(t, db)
84+
})
85+
t.Run("QueryNullMissingFieldsExamples", func(t *testing.T) {
86+
documentation_examples.QueryNullMissingFieldsExamples(t, db)
87+
})
88+
89+
mt := mtest.New(t)
90+
defer mt.Close()
5291

5392
// Because it uses RunCommand with an apiVersion, the strict count example can only be
5493
// run on 5.0+ without auth. It also cannot be run on 6.0+ since the count command was
5594
// added to API version 1 and no longer results in an error when strict is enabled.
56-
ver, err := getServerVersion(ctx, client)
57-
require.NoError(t, err, "getServerVersion error: %v", err)
58-
auth := os.Getenv("AUTH") == "auth"
59-
if testutil.CompareVersions(t, ver, "5.0") >= 0 && testutil.CompareVersions(t, ver, "6.0") < 0 && !auth {
60-
documentation_examples.StableAPIStrictCountExample(t)
61-
} else {
62-
t.Log("skipping stable API strict count example")
63-
}
95+
mtOpts := mtest.NewOptions().MinServerVersion("5.0").MaxServerVersion("5.3")
96+
mt.RunOpts("StableAPIStrictCountExample", mtOpts, func(t *mtest.T) {
97+
documentation_examples.StableAPIStrictCountExample(mt.T)
98+
})
99+
100+
mtOpts = mtest.NewOptions().MinServerVersion("5.0").Topologies(mtest.ReplicaSet, mtest.Sharded)
101+
mt.RunOpts("SnapshotQueryExamples", mtOpts, func(t *mtest.T) {
102+
documentation_examples.SnapshotQueryExamples(t)
103+
})
64104
}
65105

66106
func TestAggregationExamples(t *testing.T) {

0 commit comments

Comments
 (0)