diff --git a/internal/integration/client_test.go b/internal/integration/client_test.go index 24eb83e7f1..921aabf9bc 100644 --- a/internal/integration/client_test.go +++ b/internal/integration/client_test.go @@ -28,6 +28,7 @@ import ( "go.mongodb.org/mongo-driver/v2/mongo" "go.mongodb.org/mongo-driver/v2/mongo/options" "go.mongodb.org/mongo-driver/v2/mongo/readpref" + "go.mongodb.org/mongo-driver/v2/mongo/writeconcern" "go.mongodb.org/mongo-driver/v2/x/bsonx/bsoncore" "go.mongodb.org/mongo-driver/v2/x/mongo/driver" "go.mongodb.org/mongo-driver/v2/x/mongo/driver/wiremessage" @@ -718,6 +719,77 @@ func TestClient(t *testing.T) { }) } }) + mtBulkWriteOpts := mtest.NewOptions().MinServerVersion("8.0").AtlasDataLake(false).ClientType(mtest.Pinned) + mt.RunOpts("bulk write with nil filter", mtBulkWriteOpts, func(mt *mtest.T) { + mt.Parallel() + + testCases := []struct { + name string + models *mongo.ClientWriteModels + }{ + { + name: "DeleteOne", + models: (&mongo.ClientWriteModels{}).AppendDeleteOne("foo", "bar", mongo.NewClientDeleteOneModel()), + }, + { + name: "DeleteMany", + models: (&mongo.ClientWriteModels{}).AppendDeleteMany("foo", "bar", mongo.NewClientDeleteManyModel()), + }, + { + name: "UpdateOne", + models: (&mongo.ClientWriteModels{}).AppendUpdateOne("foo", "bar", mongo.NewClientUpdateOneModel()), + }, + { + name: "UpdateMany", + models: (&mongo.ClientWriteModels{}).AppendUpdateMany("foo", "bar", mongo.NewClientUpdateManyModel()), + }, + } + for _, tc := range testCases { + tc := tc + + mt.Run(tc.name, func(mt *mtest.T) { + mt.Parallel() + + _, err := mt.Client.BulkWrite(context.Background(), tc.models) + require.ErrorContains(mt, err, "filter is required") + }) + } + }) + mt.RunOpts("bulk write with write concern", mtBulkWriteOpts, func(mt *mtest.T) { + mt.Parallel() + + testCases := []struct { + name string + opts *options.ClientBulkWriteOptionsBuilder + want bool + }{ + { + name: "unacknowledged", + opts: options.ClientBulkWrite().SetWriteConcern(writeconcern.Unacknowledged()).SetOrdered(false), + want: false, + }, + { + name: "acknowledged", + want: true, + }, + } + for _, tc := range testCases { + tc := tc + + mt.Run(tc.name, func(mt *mtest.T) { + mt.Parallel() + + var models *mongo.ClientWriteModels + + insertOneModel := mongo.NewClientInsertOneModel().SetDocument(bson.D{{"x", 1}}) + models = (&mongo.ClientWriteModels{}).AppendInsertOne("foo", "bar", insertOneModel) + res, err := mt.Client.BulkWrite(context.Background(), models, tc.opts) + require.NoError(mt, err, "BulkWrite error: %v", err) + require.NotNil(mt, res, "expected a ClientBulkWriteResult") + assert.Equal(mt, res.Acknowledged, tc.want, "expected Acknowledged: %v, got: %v", tc.want, res.Acknowledged) + }) + } + }) } func TestClient_BSONOptions(t *testing.T) { diff --git a/internal/integration/collection_test.go b/internal/integration/collection_test.go index b370b09418..e5b4b6e4c4 100644 --- a/internal/integration/collection_test.go +++ b/internal/integration/collection_test.go @@ -1713,6 +1713,41 @@ func TestCollection(t *testing.T) { }) } }) + mt.Run("error on nil filter", func(mt *mtest.T) { + mt.Parallel() + + testCases := []struct { + name string + model mongo.WriteModel + }{ + { + name: "DeleteOne", + model: mongo.NewDeleteOneModel(), + }, + { + name: "DeleteMany", + model: mongo.NewDeleteManyModel(), + }, + { + name: "UpdateOne", + model: mongo.NewUpdateOneModel().SetUpdate(bson.D{{"$set", bson.D{{"x", 1}}}}), + }, + { + name: "UpdateMany", + model: mongo.NewUpdateManyModel().SetUpdate(bson.D{{"$set", bson.D{{"x", 1}}}}), + }, + } + for _, tc := range testCases { + tc := tc + + mt.Run(tc.name, func(mt *mtest.T) { + mt.Parallel() + + _, err := mt.Coll.BulkWrite(context.Background(), []mongo.WriteModel{tc.model}) + assert.ErrorContains(mt, err, "filter is required") + }) + } + }) mt.Run("correct model in errors", func(mt *mtest.T) { models := []mongo.WriteModel{ mongo.NewUpdateOneModel().SetFilter(bson.M{}).SetUpdate(bson.M{ diff --git a/internal/integration/crud_prose_test.go b/internal/integration/crud_prose_test.go index ed7ef35cfe..fc4a43a4f7 100644 --- a/internal/integration/crud_prose_test.go +++ b/internal/integration/crud_prose_test.go @@ -948,7 +948,7 @@ func TestClientBulkWrite(t *testing.T) { } result, err := mt.Client.BulkWrite(context.Background(), models, options.ClientBulkWrite().SetOrdered(false).SetWriteConcern(writeconcern.Unacknowledged())) require.NoError(mt, err, "BulkWrite error: %v", err) - assert.Nil(mt, result, "expected a nil result, got: %v", result) + assert.False(mt, result.Acknowledged) require.Len(mt, bwCmd, 2, "expected %d bulkWrite calls, got: %d", 2, len(bwCmd)) assert.Len(mt, bwCmd[0].Ops, numModels-1, "expected %d ops, got: %d", numModels-1, len(bwCmd[0].Ops)) diff --git a/internal/integration/unified/client_operation_execution.go b/internal/integration/unified/client_operation_execution.go index dc0c14b309..212b2c59dd 100644 --- a/internal/integration/unified/client_operation_execution.go +++ b/internal/integration/unified/client_operation_execution.go @@ -224,13 +224,13 @@ func executeClientBulkWrite(ctx context.Context, operation *operation) (*operati } res, err := client.BulkWrite(ctx, wirteModels, opts) - if res == nil { - var bwe mongo.ClientBulkWriteException - if !errors.As(err, &bwe) || bwe.PartialResult == nil { - return newDocumentResult(emptyCoreDocument, err), nil - } + var bwe mongo.ClientBulkWriteException + if errors.As(err, &bwe) { res = bwe.PartialResult } + if res == nil || !res.Acknowledged { + return newDocumentResult(emptyCoreDocument, err), nil + } rawBuilder := bsoncore.NewDocumentBuilder(). AppendInt64("deletedCount", res.DeletedCount). AppendInt64("insertedCount", res.InsertedCount). diff --git a/mongo/bulk_write.go b/mongo/bulk_write.go index 5838f141ae..cbd2f7f2a4 100644 --- a/mongo/bulk_write.go +++ b/mongo/bulk_write.go @@ -9,6 +9,7 @@ package mongo import ( "context" "errors" + "fmt" "go.mongodb.org/mongo-driver/v2/bson" "go.mongodb.org/mongo-driver/v2/mongo/options" @@ -296,6 +297,9 @@ func createDeleteDoc( ) (bsoncore.Document, error) { f, err := marshal(filter, bsonOpts, registry) if err != nil { + if filter == nil { + return nil, fmt.Errorf("%w: filter is required", err) + } return nil, err } @@ -428,6 +432,9 @@ type updateDoc struct { func (doc updateDoc) marshal(bsonOpts *options.BSONOptions, registry *bson.Registry) (bsoncore.Document, error) { f, err := marshal(doc.filter, bsonOpts, registry) if err != nil { + if doc.filter == nil { + return nil, fmt.Errorf("%w: filter is required", err) + } return nil, err } diff --git a/mongo/bulk_write_models.go b/mongo/bulk_write_models.go index 84902a0299..6a62441dd8 100644 --- a/mongo/bulk_write_models.go +++ b/mongo/bulk_write_models.go @@ -20,6 +20,8 @@ type WriteModel interface { } // InsertOneModel is used to insert a single document in a BulkWrite operation. +// +// See corresponding setter methods for documentation. type InsertOneModel struct { Document interface{} } @@ -40,6 +42,8 @@ func (iom *InsertOneModel) SetDocument(doc interface{}) *InsertOneModel { func (*InsertOneModel) writeModel() {} // DeleteOneModel is used to delete at most one document in a BulkWriteOperation. +// +// See corresponding setter methods for documentation. type DeleteOneModel struct { Filter interface{} Collation *options.Collation @@ -80,6 +84,8 @@ func (dom *DeleteOneModel) SetHint(hint interface{}) *DeleteOneModel { func (*DeleteOneModel) writeModel() {} // DeleteManyModel is used to delete multiple documents in a BulkWrite operation. +// +// See corresponding setter methods for documentation. type DeleteManyModel struct { Filter interface{} Collation *options.Collation @@ -119,6 +125,8 @@ func (dmm *DeleteManyModel) SetHint(hint interface{}) *DeleteManyModel { func (*DeleteManyModel) writeModel() {} // ReplaceOneModel is used to replace at most one document in a BulkWrite operation. +// +// See corresponding setter methods for documentation. type ReplaceOneModel struct { Collation *options.Collation Upsert *bool @@ -176,6 +184,8 @@ func (rom *ReplaceOneModel) SetUpsert(upsert bool) *ReplaceOneModel { func (*ReplaceOneModel) writeModel() {} // UpdateOneModel is used to update at most one document in a BulkWrite operation. +// +// See corresponding setter methods for documentation. type UpdateOneModel struct { Collation *options.Collation Upsert *bool @@ -241,6 +251,8 @@ func (uom *UpdateOneModel) SetUpsert(upsert bool) *UpdateOneModel { func (*UpdateOneModel) writeModel() {} // UpdateManyModel is used to update multiple documents in a BulkWrite operation. +// +// See corresponding setter methods for documentation. type UpdateManyModel struct { Collation *options.Collation Upsert *bool diff --git a/mongo/client.go b/mongo/client.go index 6bc3290b2a..c0a721f167 100644 --- a/mongo/client.go +++ b/mongo/client.go @@ -895,10 +895,14 @@ func (c *Client) createBaseCursorOptions() driver.CursorOptions { // BulkWrite performs a client-level bulk write operation. func (c *Client) BulkWrite(ctx context.Context, models *ClientWriteModels, opts ...options.Lister[options.ClientBulkWriteOptions]) (*ClientBulkWriteResult, error) { - // TODO: Remove once DRIVERS-2888 is implemented. + // TODO(GODRIVER-3403): Remove after support for QE with Client.bulkWrite. if c.isAutoEncryptionSet { return nil, errors.New("bulkWrite does not currently support automatic encryption") } + + if models == nil { + return nil, ErrNilValue + } bwo, err := mongoutil.NewOptions(opts...) if err != nil { return nil, err @@ -962,14 +966,9 @@ func (c *Client) BulkWrite(ctx context.Context, models *ClientWriteModels, } else if !acknowledged { return nil, errors.New("cannot request unacknowledged write concern and verbose results") } - if err = op.execute(ctx); err != nil { - return nil, replaceErrors(err) - } - var results *ClientBulkWriteResult - if acknowledged { - results = &op.result - } - return results, nil + op.result.Acknowledged = acknowledged + err = op.execute(ctx) + return &op.result, replaceErrors(err) } // newLogger will use the LoggerOptions to create an internal logger and publish diff --git a/mongo/client_bulk_write.go b/mongo/client_bulk_write.go index 13b3085a52..ed29a74289 100644 --- a/mongo/client_bulk_write.go +++ b/mongo/client_bulk_write.go @@ -10,6 +10,7 @@ import ( "bytes" "context" "errors" + "fmt" "io" "strconv" @@ -81,19 +82,16 @@ func (bw *clientBulkWrite) execute(ctx context.Context) error { Name: driverutil.BulkWriteOp, }.Execute(ctx) var exception *ClientBulkWriteException - switch tt := err.(type) { - case CommandError: + + var ce CommandError + if errors.As(err, &ce) { exception = &ClientBulkWriteException{ TopLevelError: &WriteError{ - Code: int(tt.Code), - Message: tt.Message, - Raw: tt.Raw, + Code: int(ce.Code), + Message: ce.Message, + Raw: ce.Raw, }, } - default: - if errors.Is(err, driver.ErrUnacknowledgedWrite) { - err = nil - } } if len(batches.writeConcernErrors) > 0 || len(batches.writeErrors) > 0 { if exception == nil { @@ -453,11 +451,13 @@ func (mb *modelBatches) processResponse(ctx context.Context, resp bsoncore.Docum } } - mb.result.DeletedCount += int64(res.NDeleted) - mb.result.InsertedCount += int64(res.NInserted) - mb.result.MatchedCount += int64(res.NMatched) - mb.result.ModifiedCount += int64(res.NModified) - mb.result.UpsertedCount += int64(res.NUpserted) + if mb.result.Acknowledged { + mb.result.DeletedCount += int64(res.NDeleted) + mb.result.InsertedCount += int64(res.NInserted) + mb.result.MatchedCount += int64(res.NMatched) + mb.result.ModifiedCount += int64(res.NModified) + mb.result.UpsertedCount += int64(res.NUpserted) + } var cursorRes driver.CursorResponse cursorRes, err = driver.NewCursorResponse(res.Cursor, info) @@ -520,10 +520,12 @@ func (mb *modelBatches) appendDeleteResult(cur *cursorInfo, raw bson.Raw) bool { return false } - if mb.result.DeleteResults == nil { - mb.result.DeleteResults = make(map[int]ClientDeleteResult) + if mb.result.Acknowledged { + if mb.result.DeleteResults == nil { + mb.result.DeleteResults = make(map[int]ClientBulkWriteDeleteResult) + } + mb.result.DeleteResults[idx] = ClientBulkWriteDeleteResult{int64(cur.N)} } - mb.result.DeleteResults[idx] = ClientDeleteResult{int64(cur.N)} return true } @@ -539,10 +541,12 @@ func (mb *modelBatches) appendInsertResult(cur *cursorInfo, raw bson.Raw) bool { return false } - if mb.result.InsertResults == nil { - mb.result.InsertResults = make(map[int]ClientInsertResult) + if mb.result.Acknowledged { + if mb.result.InsertResults == nil { + mb.result.InsertResults = make(map[int]ClientBulkWriteInsertResult) + } + mb.result.InsertResults[idx] = ClientBulkWriteInsertResult{mb.newIDMap[idx]} } - mb.result.InsertResults[idx] = ClientInsertResult{mb.newIDMap[idx]} return true } @@ -558,19 +562,21 @@ func (mb *modelBatches) appendUpdateResult(cur *cursorInfo, raw bson.Raw) bool { return false } - if mb.result.UpdateResults == nil { - mb.result.UpdateResults = make(map[int]ClientUpdateResult) - } - result := ClientUpdateResult{ - MatchedCount: int64(cur.N), - } - if cur.NModified != nil { - result.ModifiedCount = int64(*cur.NModified) - } - if cur.Upserted != nil { - result.UpsertedID = cur.Upserted.ID + if mb.result.Acknowledged { + if mb.result.UpdateResults == nil { + mb.result.UpdateResults = make(map[int]ClientBulkWriteUpdateResult) + } + result := ClientBulkWriteUpdateResult{ + MatchedCount: int64(cur.N), + } + if cur.NModified != nil { + result.ModifiedCount = int64(*cur.NModified) + } + if cur.Upserted != nil { + result.UpsertedID = cur.Upserted.ID + } + mb.result.UpdateResults[idx] = result } - mb.result.UpdateResults[idx] = result return true } @@ -624,6 +630,9 @@ func (d *clientUpdateDoc) marshal(bsonOpts *options.BSONOptions, registry *bson. f, err := marshal(d.filter, bsonOpts, registry) if err != nil { + if d.filter == nil { + return nil, fmt.Errorf("%w: filter is required", err) + } return nil, err } doc = bsoncore.AppendDocumentElement(doc, "filter", f) @@ -684,6 +693,9 @@ func (d *clientDeleteDoc) marshal(bsonOpts *options.BSONOptions, registry *bson. f, err := marshal(d.filter, bsonOpts, registry) if err != nil { + if d.filter == nil { + return nil, fmt.Errorf("%w: filter is required", err) + } return nil, err } doc = bsoncore.AppendDocumentElement(doc, "filter", f) diff --git a/mongo/client_bulk_write_models.go b/mongo/client_bulk_write_models.go index b1ed7f5eb9..51208a8710 100644 --- a/mongo/client_bulk_write_models.go +++ b/mongo/client_bulk_write_models.go @@ -35,8 +35,13 @@ func (m *ClientWriteModels) AppendInsertOne(database, collection string, models return m } -// AppendUpdateOne appends ClientUpdateOneModels. -func (m *ClientWriteModels) AppendUpdateOne(database, collection string, models ...*ClientUpdateOneModel) *ClientWriteModels { +// appendModels is a helper function to append models to ClientWriteModels. +func appendModels[T ClientUpdateOneModel | + ClientUpdateManyModel | + ClientReplaceOneModel | + ClientDeleteOneModel | + ClientDeleteManyModel]( + m *ClientWriteModels, database, collection string, models []*T) *ClientWriteModels { if m == nil { m = &ClientWriteModels{} } @@ -49,63 +54,34 @@ func (m *ClientWriteModels) AppendUpdateOne(database, collection string, models return m } +// AppendUpdateOne appends ClientUpdateOneModels. +func (m *ClientWriteModels) AppendUpdateOne(database, collection string, models ...*ClientUpdateOneModel) *ClientWriteModels { + return appendModels(m, database, collection, models) +} + // AppendUpdateMany appends ClientUpdateManyModels. func (m *ClientWriteModels) AppendUpdateMany(database, collection string, models ...*ClientUpdateManyModel) *ClientWriteModels { - if m == nil { - m = &ClientWriteModels{} - } - for _, model := range models { - m.models = append(m.models, clientWriteModel{ - namespace: fmt.Sprintf("%s.%s", database, collection), - model: model, - }) - } - return m + return appendModels(m, database, collection, models) } // AppendReplaceOne appends ClientReplaceOneModels. func (m *ClientWriteModels) AppendReplaceOne(database, collection string, models ...*ClientReplaceOneModel) *ClientWriteModels { - if m == nil { - m = &ClientWriteModels{} - } - for _, model := range models { - m.models = append(m.models, clientWriteModel{ - namespace: fmt.Sprintf("%s.%s", database, collection), - model: model, - }) - } - return m + return appendModels(m, database, collection, models) } // AppendDeleteOne appends ClientDeleteOneModels. func (m *ClientWriteModels) AppendDeleteOne(database, collection string, models ...*ClientDeleteOneModel) *ClientWriteModels { - if m == nil { - m = &ClientWriteModels{} - } - for _, model := range models { - m.models = append(m.models, clientWriteModel{ - namespace: fmt.Sprintf("%s.%s", database, collection), - model: model, - }) - } - return m + return appendModels(m, database, collection, models) } // AppendDeleteMany appends ClientDeleteManyModels. func (m *ClientWriteModels) AppendDeleteMany(database, collection string, models ...*ClientDeleteManyModel) *ClientWriteModels { - if m == nil { - m = &ClientWriteModels{} - } - for _, model := range models { - m.models = append(m.models, clientWriteModel{ - namespace: fmt.Sprintf("%s.%s", database, collection), - model: model, - }) - } - return m + return appendModels(m, database, collection, models) } // ClientInsertOneModel is used to insert a single document in a client-level BulkWrite operation. +// +// See corresponding setter methods for documentation. type ClientInsertOneModel struct { Document interface{} } @@ -124,6 +100,8 @@ func (iom *ClientInsertOneModel) SetDocument(doc interface{}) *ClientInsertOneMo } // ClientUpdateOneModel is used to update at most one document in a client-level BulkWrite operation. +// +// See corresponding setter methods for documentation. type ClientUpdateOneModel struct { Collation *options.Collation Upsert *bool @@ -183,6 +161,8 @@ func (uom *ClientUpdateOneModel) SetUpsert(upsert bool) *ClientUpdateOneModel { } // ClientUpdateManyModel is used to update multiple documents in a client-level BulkWrite operation. +// +// See corresponding setter methods for documentation. type ClientUpdateManyModel struct { Collation *options.Collation Upsert *bool @@ -241,6 +221,8 @@ func (umm *ClientUpdateManyModel) SetUpsert(upsert bool) *ClientUpdateManyModel } // ClientReplaceOneModel is used to replace at most one document in a client-level BulkWrite operation. +// +// See corresponding setter methods for documentation. type ClientReplaceOneModel struct { Collation *options.Collation Upsert *bool @@ -292,6 +274,8 @@ func (rom *ClientReplaceOneModel) SetUpsert(upsert bool) *ClientReplaceOneModel } // ClientDeleteOneModel is used to delete at most one document in a client-level BulkWriteOperation. +// +// See corresponding setter methods for documentation. type ClientDeleteOneModel struct { Filter interface{} Collation *options.Collation @@ -326,6 +310,8 @@ func (dom *ClientDeleteOneModel) SetHint(hint interface{}) *ClientDeleteOneModel } // ClientDeleteManyModel is used to delete multiple documents in a client-level BulkWrite operation. +// +// See corresponding setter methods for documentation. type ClientDeleteManyModel struct { Filter interface{} Collation *options.Collation diff --git a/mongo/client_bulk_write_test.go b/mongo/client_bulk_write_test.go index 9d46ffccb3..37c6e1f017 100644 --- a/mongo/client_bulk_write_test.go +++ b/mongo/client_bulk_write_test.go @@ -15,7 +15,11 @@ import ( ) func TestBatches(t *testing.T) { + t.Parallel() + t.Run("test Addvancing", func(t *testing.T) { + t.Parallel() + batches := &modelBatches{ models: make([]clientWriteModel, 2), } @@ -24,6 +28,8 @@ func TestBatches(t *testing.T) { assert.Equal(t, 0, size, "expected: %d, got: %d", 1, size) }) t.Run("test appendBatches", func(t *testing.T) { + t.Parallel() + client, err := newClient() require.NoError(t, err, "NewClient error: %v", err) batches := &modelBatches{ diff --git a/mongo/errors.go b/mongo/errors.go index b8f6090c4f..3c5258c109 100644 --- a/mongo/errors.go +++ b/mongo/errors.go @@ -260,6 +260,8 @@ var _ ServerError = WriteError{} var _ ServerError = WriteException{} var _ ServerError = BulkWriteException{} +var _ error = ClientBulkWriteException{} + // CommandError represents a server error during execution of a command. This can be returned by any operation. type CommandError struct { Code int32 diff --git a/mongo/options/clientbulkwriteoptions.go b/mongo/options/clientbulkwriteoptions.go index 3d9a4cb92e..a55ac27f05 100644 --- a/mongo/options/clientbulkwriteoptions.go +++ b/mongo/options/clientbulkwriteoptions.go @@ -11,29 +11,15 @@ import ( ) // ClientBulkWriteOptions represents options that can be used to configure a client-level BulkWrite operation. +// +// See corresponding setter methods for documentation. type ClientBulkWriteOptions struct { - // If true, writes executed as part of the operation will opt out of document-level validation on the server. The - // default value is false. See https://www.mongodb.com/docs/manual/core/schema-validation/ for more information - // about document validation. BypassDocumentValidation *bool - - // A string or document that will be included in server logs, profiling logs, and currentOp queries to help trace - // the operation. The default value is nil, which means that no comment will be included in the logs. - Comment interface{} - - // If true, no writes will be executed after one fails. The default value is true. - Ordered *bool - - // Specifies parameters for all update and delete commands in the BulkWrite. This must be a document mapping - // parameter names to values. Values must be constant or closed expressions that do not reference document fields. - // Parameters can then be accessed as variables in an aggregate expression context (e.g. "$$var"). - Let interface{} - - // The write concern to use for this bulk write. - WriteConcern *writeconcern.WriteConcern - - // Whether detailed results for each successful operation should be included in the returned BulkWriteResult. - VerboseResults *bool + Comment interface{} + Ordered *bool + Let interface{} + WriteConcern *writeconcern.WriteConcern + VerboseResults *bool } // ClientBulkWriteOptionsBuilder contains options to configure client-level bulk diff --git a/mongo/results.go b/mongo/results.go index 92474a8466..1e00b2eca6 100644 --- a/mongo/results.go +++ b/mongo/results.go @@ -31,30 +31,34 @@ type ClientBulkWriteResult struct { UpsertedCount int64 // A map of operation index to the _id of each inserted document. - InsertResults map[int]ClientInsertResult + InsertResults map[int]ClientBulkWriteInsertResult // A map of operation index to the _id of each updated document. - UpdateResults map[int]ClientUpdateResult + UpdateResults map[int]ClientBulkWriteUpdateResult // A map of operation index to the _id of each deleted document. - DeleteResults map[int]ClientDeleteResult + DeleteResults map[int]ClientBulkWriteDeleteResult + + // Operation performed with an acknowledged write. Values for other fields may + // not be deterministic if the write operation was unacknowledged. + Acknowledged bool } -// ClientInsertResult is the result type returned by a client-level bulk write of InsertOne operation. -type ClientInsertResult struct { +// ClientBulkWriteInsertResult is the result type returned by a client-level bulk write of InsertOne operation. +type ClientBulkWriteInsertResult struct { // The _id of the inserted document. A value generated by the driver will be of type primitive.ObjectID. InsertedID interface{} } -// ClientUpdateResult is the result type returned from a client-level bulk write of UpdateOne, UpdateMany, and ReplaceOne operation. -type ClientUpdateResult struct { +// ClientBulkWriteUpdateResult is the result type returned from a client-level bulk write of UpdateOne, UpdateMany, and ReplaceOne operation. +type ClientBulkWriteUpdateResult struct { MatchedCount int64 // The number of documents matched by the filter. ModifiedCount int64 // The number of documents modified by the operation. UpsertedID interface{} // The _id field of the upserted document, or nil if no upsert was done. } -// ClientDeleteResult is the result type returned by a client-level bulk write DeleteOne and DeleteMany operation. -type ClientDeleteResult struct { +// ClientBulkWriteDeleteResult is the result type returned by a client-level bulk write DeleteOne and DeleteMany operation. +type ClientBulkWriteDeleteResult struct { DeletedCount int64 // The number of documents deleted. }