Skip to content

Commit 370e317

Browse files
author
Divjot Arora
authored
GODRIVER-1147 Add an API to create collections (#351)
1 parent 6d539cd commit 370e317

File tree

7 files changed

+966
-0
lines changed

7 files changed

+966
-0
lines changed

mongo/crud_examples_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,62 @@ func ExampleClient_Watch() {
5858

5959
// Database examples
6060

61+
func 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+
91+
func 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+
61117
func ExampleDatabase_ListCollectionNames() {
62118
var db *mongo.Database
63119

mongo/database.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"go.mongodb.org/mongo-driver/mongo/readpref"
1919
"go.mongodb.org/mongo-driver/mongo/writeconcern"
2020
"go.mongodb.org/mongo-driver/x/bsonx"
21+
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
2122
"go.mongodb.org/mongo-driver/x/mongo/driver"
2223
"go.mongodb.org/mongo-driver/x/mongo/driver/description"
2324
"go.mongodb.org/mongo-driver/x/mongo/driver/operation"
@@ -432,3 +433,135 @@ func (db *Database) Watch(ctx context.Context, pipeline interface{},
432433
}
433434
return newChangeStream(ctx, csConfig, pipeline, opts...)
434435
}
436+
437+
// CreateCollection executes a create command to explicitly create a new collection with the specified name on the
438+
// server. If the collection being created already exists, this method will return a mongo.CommandError. This method
439+
// requires driver version 1.4.0 or higher.
440+
//
441+
// The opts parameter can be used to specify options for the operation (see the options.CreateCollectionOptions
442+
// documentation).
443+
func (db *Database) CreateCollection(ctx context.Context, name string, opts ...*options.CreateCollectionOptions) error {
444+
cco := options.MergeCreateCollectionOptions(opts...)
445+
op := operation.NewCreate(name)
446+
447+
if cco.Capped != nil {
448+
op.Capped(*cco.Capped)
449+
}
450+
if cco.Collation != nil {
451+
op.Collation(bsoncore.Document(cco.Collation.ToDocument()))
452+
}
453+
if cco.DefaultIndexOptions != nil {
454+
idx, doc := bsoncore.AppendDocumentStart(nil)
455+
if cco.DefaultIndexOptions.StorageEngine != nil {
456+
storageEngine, err := transformBsoncoreDocument(db.registry, cco.DefaultIndexOptions.StorageEngine)
457+
if err != nil {
458+
return err
459+
}
460+
461+
doc = bsoncore.AppendDocumentElement(doc, "storageEngine", storageEngine)
462+
}
463+
doc, err := bsoncore.AppendDocumentEnd(doc, idx)
464+
if err != nil {
465+
return err
466+
}
467+
468+
op.IndexOptionDefaults(doc)
469+
}
470+
if cco.MaxDocuments != nil {
471+
op.Max(*cco.MaxDocuments)
472+
}
473+
if cco.SizeInBytes != nil {
474+
op.Size(*cco.SizeInBytes)
475+
}
476+
if cco.StorageEngine != nil {
477+
storageEngine, err := transformBsoncoreDocument(db.registry, cco.StorageEngine)
478+
if err != nil {
479+
return err
480+
}
481+
op.StorageEngine(storageEngine)
482+
}
483+
if cco.ValidationAction != nil {
484+
op.ValidationAction(*cco.ValidationAction)
485+
}
486+
if cco.ValidationLevel != nil {
487+
op.ValidationLevel(*cco.ValidationLevel)
488+
}
489+
if cco.Validator != nil {
490+
validator, err := transformBsoncoreDocument(db.registry, cco.Validator)
491+
if err != nil {
492+
return err
493+
}
494+
op.Validator(validator)
495+
}
496+
497+
return db.executeCreateOperation(ctx, op)
498+
}
499+
500+
// CreateView executes a create command to explicitly create a view on the server. See
501+
// https://docs.mongodb.com/manual/core/views/ for more information about views. This method requires driver version >=
502+
// 1.4.0 and MongoDB version >= 3.4.
503+
//
504+
// The viewName parameter specifies the name of the view to create.
505+
//
506+
// The viewOn parameter specifies the name of the collection or view on which this view will be created
507+
//
508+
// The pipeline parameter specifies an aggregation pipeline that will be exececuted against the source collection or
509+
// view to create this view.
510+
//
511+
// The opts parameter can be used to specify options for the operation (see the options.CreateViewOptions
512+
// documentation).
513+
func (db *Database) CreateView(ctx context.Context, viewName, viewOn string, pipeline interface{},
514+
opts ...*options.CreateViewOptions) error {
515+
516+
pipelineArray, _, err := transformAggregatePipelinev2(db.registry, pipeline)
517+
if err != nil {
518+
return err
519+
}
520+
521+
op := operation.NewCreate(viewName).
522+
ViewOn(viewOn).
523+
Pipeline(pipelineArray)
524+
cvo := options.MergeCreateViewOptions(opts...)
525+
if cvo.Collation != nil {
526+
op.Collation(bsoncore.Document(cvo.Collation.ToDocument()))
527+
}
528+
529+
return db.executeCreateOperation(ctx, op)
530+
}
531+
532+
func (db *Database) executeCreateOperation(ctx context.Context, op *operation.Create) error {
533+
sess := sessionFromContext(ctx)
534+
if sess == nil && db.client.sessionPool != nil {
535+
var err error
536+
sess, err = session.NewClientSession(db.client.sessionPool, db.client.id, session.Implicit)
537+
if err != nil {
538+
return err
539+
}
540+
defer sess.EndSession()
541+
}
542+
543+
err := db.client.validSession(sess)
544+
if err != nil {
545+
return err
546+
}
547+
548+
wc := db.writeConcern
549+
if sess.TransactionRunning() {
550+
wc = nil
551+
}
552+
if !writeconcern.AckWrite(wc) {
553+
sess = nil
554+
}
555+
556+
selector := makePinnedSelector(sess, db.writeSelector)
557+
op = op.Session(sess).
558+
WriteConcern(wc).
559+
CommandMonitor(db.client.monitor).
560+
ServerSelector(selector).
561+
ClusterClock(db.client.clock).
562+
Database(db.name).
563+
Deployment(db.client.deployment).
564+
Crypt(db.client.crypt)
565+
566+
return replaceErrors(op.Execute(ctx))
567+
}

0 commit comments

Comments
 (0)