Skip to content

GODRIVER-2388 Improved Bulk Write API. #1884

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 15 commits into from
Jan 24, 2025

Conversation

qingyang-hu
Copy link
Collaborator

@qingyang-hu qingyang-hu commented Nov 5, 2024

GODRIVER-2388
GODRIVER-3348
GODRIVER-3349
GODRIVER-3364

GODRIVER-3421 (added in fc91428)

Summary

Improved Bulk Write API.

Background & Motivation

Refactor the (Operation).createWireMessage() to support the bulk write batching.

@mongodb-drivers-pr-bot mongodb-drivers-pr-bot bot added the priority-3-low Low Priority PR for Review label Nov 5, 2024
Copy link
Contributor

mongodb-drivers-pr-bot bot commented Nov 5, 2024

API Change Report

./v2/mongo

incompatible changes

(*ReplaceOneModel).SetSort: removed
(*UpdateOneModel).SetSort: removed
ReplaceOneModel.Sort: removed
UpdateOneModel.Sort: removed

compatible changes

(*Client).BulkWrite: added
ClientBulkWrite: added
ClientBulkWriteDeleteResult: added
ClientBulkWriteException: added
ClientBulkWriteInsertResult: added
ClientBulkWriteResult: added
ClientBulkWriteUpdateResult: added
ClientDeleteManyModel: added
ClientDeleteOneModel: added
ClientInsertOneModel: added
ClientReplaceOneModel: added
ClientUpdateManyModel: added
ClientUpdateOneModel: added
ClientWriteModel: added
NewClientDeleteManyModel: added
NewClientDeleteOneModel: added
NewClientInsertOneModel: added
NewClientReplaceOneModel: added
NewClientUpdateManyModel: added
NewClientUpdateOneModel: added

./v2/mongo/options

incompatible changes

(*ReplaceOptionsBuilder).SetSort: removed
(*UpdateOneOptionsBuilder).SetSort: removed
ReplaceOptions.Sort: removed
UpdateOneOptions.Sort: removed

compatible changes

ClientBulkWrite: added
ClientBulkWriteOptions: added
ClientBulkWriteOptionsBuilder: added

./v2/x/mongo/driver

incompatible changes

(*Batches).AdvanceBatch: removed
(*Batches).ClearBatch: removed
(*Batches).Valid: removed
Batches.Current: removed
##NewCursorResponse: changed from func(ResponseInfo) (CursorResponse, error) to func(./v2/x/bsonx/bsoncore.Document, ResponseInfo) (CursorResponse, error)
Operation.Batches: changed from *Batches to OperationBatches
##Operation.ProcessResponseFn: changed from func(ResponseInfo) error to func(context.Context, ./v2/x/bsonx/bsoncore.Document, ResponseInfo) error
ResponseInfo.ServerResponse: removed

compatible changes

(*Batches).AdvanceBatches: added
(*Batches).AppendBatchArray: added
(*Batches).AppendBatchSequence: added
(*Batches).IsOrdered: added
(*Batches).Size: added
ExtractCursorDocument: added
OperationBatches: added
ResponseInfo.Error: added

./v2/x/mongo/driver/session

incompatible changes

Client.RetryRead: removed
Client.RetryWrite: removed

@@ -398,7 +398,7 @@ func TestClientSideEncryptionCustomCrypt(t *testing.T) {
"expected 0 calls to DecryptExplicit, got %v", cc.numDecryptExplicitCalls)
assert.Equal(mt, cc.numCloseCalls, 0,
"expected 0 calls to Close, got %v", cc.numCloseCalls)
assert.Equal(mt, cc.numBypassAutoEncryptionCalls, 2,
assert.Equal(mt, cc.numBypassAutoEncryptionCalls, 1,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only call it once after the operation.go refactoring.

mongo/errors.go Outdated
// A top-level error that occurred when attempting to communicate with the server
// or execute the bulk write. This value may not be populated if the exception was
// thrown due to errors occurring on individual writes.
TopLevelError *WriteError
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cannot use Error as a field name because of the conflict with the conventional method name.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: Consider the more conventional Err or WriteError.

@qingyang-hu qingyang-hu marked this pull request as ready for review November 5, 2024 20:18
@qingyang-hu qingyang-hu added priority-2-medium Medium Priority PR for Review and removed priority-3-low Low Priority PR for Review labels Nov 5, 2024
}
type clientWriteModel struct {
namespace string
model interface{}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add stronger type constraints to this?

type clientBulkWriteModel interface {
	ClientInsertOneModel // etc.
}

type clientWriteModel struct {
	namespace string
	model     clientBulkWriteModel
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need an additional abstraction for an un-exported struct.

}

// Error implements the error interface.
func (bwe ClientBulkWriteException) Error() string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function doesn't return an error if the write is unacknowledged. The specifications required that users be able to discern whether a BulkWriteResult contains acknowledged results. Either return an error indicating an unacknowledged result, or update ClientBulkWriteResult in the spirit of GODRIVER-2821.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can test this with the following:

package main

import (
	"context"

	"go.mongodb.org/mongo-driver/v2/bson"
	"go.mongodb.org/mongo-driver/v2/mongo"
	"go.mongodb.org/mongo-driver/v2/mongo/options"
	"go.mongodb.org/mongo-driver/v2/mongo/writeconcern"
)

func main() {
	client, err := mongo.Connect()
	if err != nil {
		panic(err)
	}

	defer func() { _ = client.Disconnect(context.Background()) }()

	pairs := &mongo.ClientWriteModels{}

	insertOneModel := mongo.NewClientInsertOneModel().SetDocument(bson.D{{"x", 1}})

	opts := options.ClientBulkWrite().SetWriteConcern(writeconcern.Unacknowledged()).SetOrdered(false)

	pairs = pairs.AppendInsertOne("db", "k", insertOneModel)
	_, err = client.BulkWrite(context.Background(), pairs, opts) // Should not panic
	if err != nil {
		panic(err)
	}
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a unified spec test that covers this case? If not we should add one / add an integration test.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 300 to 302
if filter == nil {
return nil, fmt.Errorf("%w: filter is required", err)
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update the error message when the filter is not given.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to nest this nil filter check in this error handling block? Can we move this check to the beginning of marshal?

Optional: Consider a clearer error message, like

delete filter cannot be nil

Comment on lines 435 to 437
if doc.filter == nil {
return nil, fmt.Errorf("%w: filter is required", err)
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update the error message when the filter is not given.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to nest this nil filter check in this error handling block? Can we move this check to the beginning of marshal?

Optional: Consider a clearer error message, like

update filter cannot be nil

@qingyang-hu qingyang-hu force-pushed the godriver2388v2 branch 4 times, most recently from 4bc724e to dbd44c9 Compare November 15, 2024 23:14
Copy link
Member

@prestonvasquez prestonvasquez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@qingyang-hu There are still outstanding issues from the previous review.

@@ -13,6 +13,55 @@ import (
"go.mongodb.org/mongo-driver/v2/x/mongo/driver/operation"
)

// ClientBulkWriteResult is the result type returned by a client-level BulkWrite operation.
type ClientBulkWriteResult struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The specifications say that "Users MUST be able to discern whether a [result] contains verbose results without inspecting the value provided for verboseResults in [options]". Does this mean we should add a boolean value ClientBulkWriteResult: HasVerboseResults?

Copy link
Collaborator Author

@qingyang-hu qingyang-hu Nov 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The initial thought was to leave results maps as nil when verboseResults is false. However, I think you are right that an additional HasVerboseResults field is more obvious.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, either solution sounds good to me.

},
}
var n int
n, _, err = batches.AppendBatchSequence(nil, 4, 16_000, 16_000)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the significance of 16_000 here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is just a number big enough not to cut the document, so only the maxCount regulates the output. Will add a comment there.

var idx int32
dst = wiremessage.AppendMsgSectionType(dst, wiremessage.DocumentSequence)
idx, dst = bsoncore.ReserveLength(dst)
dst = append(dst, identifier...)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the specifications:

The first entry in each document has the name of the operation as its key and the index ini the nsInfo array of the namespace on which the operation should be performed as its value

When I do command monitoring for client bulk write with multiple pairs, I get the following:

2024/11/18 14:39:47 started: &{Command:{"bulkWrite": {"$numberInt":"1"},"errorsOnly": false,"ordered": true,"lsid": {"id": {"$binary":{"base64":"XTDtLVGhTx6MEIcFDhf0qw==","subType":"04"}}},"txnNumber": {"$numberLong":"1"},"$clusterTime": {"clusterTime": {"$timestamp":{"t":1731965987,"i":1}},"signature": {"hash": {"$binary":{"base64":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","subType":"00"}},"keyId": {"$numberLong":"0"}}},"$db": "admin","ops": [{"insert": {"$numberInt":"0"},"document": {"_id": {"$oid":"673bb423a86efe4126c4c585"},"x": {"$numberInt":"1"}}},{"insert": {"$numberInt":"0"},"document": {"_id": {"$oid":"673bb423a86efe4126c4c586"},"x": {"$numberInt":"2"}}}],"nsInfo": [{"ns": "db.coll"}]} DatabaseName:admin CommandName:bulkWrite RequestID:1 ConnectionID:localhost:27017[-4] ServerConnectionID:0x14000390250 ServiceID:<nil>}

Where the index value for each document in the sequence is {"$numberInt":"0"}. Shouldn't this be {"$numberInt":"0"}, then {"$numberInt":"1"}, etc?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same thing occurs with the other client bulk write operations.

Copy link
Collaborator Author

@qingyang-hu qingyang-hu Nov 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean the Int32 value of the operation name such as "insert", "update", or "delete"?

...
"ops":[
    {
        "insert":{
            "$numberInt":"0"
        },
...

It is "the index in the nsInfo array of the namespace on which the operation should be performed as its value".

The specs also require:

When constructing the nsInfo array for a bulkWrite batch, drivers MUST only include the namespaces that are referenced in the ops array for that batch.

and:

Drivers MUST NOT include duplicate namespaces in this list.

Therefore, if both operations perform on the same namespace, the nsInfo array should contain only one item, and both operation indices are 0, pointing to "db.coll".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, thanks for the explanation!

// AppendBatchSequence appends dst with document sequence of batches as long as the limits of max count, max
// document size, or total size allows. It returns the number of batches appended, the new appended slice, and
// any error raised. It returns the origenal input slice if nothing can be appends within the limits.
func (b *Batches) AppendBatchSequence(dst []byte, maxCount, maxDocSize, _ int) (int, []byte, error) {
Copy link
Member

@prestonvasquez prestonvasquez Dec 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does maxMessageSizeBytes not apply when not using bulk write? For example, when using collection.Insert would we batch up to 48mb or 16mb? If I understand the documentation correctly, the batch has a limit of 48mb and individual documents in the batch have a limit of 16mb. Right now it appears we are limiting the entire batch to 16mb. The clientBulkWrite API does what I would expect.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic derives from the original *Batches.AdvanceBatch(), which takes maxDocumentSize as maxMessageSizeBytes. A test case covers the logic here.

@matthewdale, do you know any history of the logic?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated the logic in fc91428.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we open a ticket for this to avoid adding more complexity to this PR?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, it doesn't make sense to review incorrect logic since we've already refactored that block. Moreover, fc91428 removed the maxBsonObjectSize requirement from the client-level bulk write to simplify the PR.

However, I'm open to reverting and only keeping what is more relevant.

Copy link
Member

@prestonvasquez prestonvasquez Dec 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIU the updated solution correctly it is now possible to put a single document over the 16mb limit on the wire message, relying on the server to validate the document size. From what I can tell, this is spec-compliant. But do we want to make data-heavy round trips that we know are going to fail?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, both the client-level bulk write and legacy bulk write rely on the server to check the document size limit in fc91428.

But I agree the validation on the server side is inefficient. Pre-validating the size on the driver side is not a breach of the spec because it is not prohibited, either, especially for performance reasons. So I will commit another change to return driver side errors.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW IMO we can defer that work.

@@ -268,7 +271,13 @@ type Operation struct {
// has more documents than can fit in a single command. This should only be specified for
// commands that are batch compatible. For more information, please refer to the definition of
// Batches.
Batches *Batches
Batches interface {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest internalizing this interface so that we can create a compile check for mongo.modelBatches and x/mongo.Batches.

return len(mb.models) - mb.offset
}

func (mb *modelBatches) AppendBatchSequence(dst []byte, maxCount, maxDocSize, totalSize int) (int, []byte, error) {
Copy link
Member

@prestonvasquez prestonvasquez Dec 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have test coverage for this in the following two cases:

  1. One doc exceeds maxBsonObjectSize, I would expect an error.
  2. Multiple documents < maxBsonObjectSize together exceed maxMessageSizeBytes. I would expect n > 1.

Here is a helpful gist I used: https://gist.github.com/prestonvasquez/40daa306abc5a21147235d2ea982d841

Copy link
Collaborator Author

@qingyang-hu qingyang-hu Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've involved GODRIVER-3421 in fc91428, which removes the BSON document size validation requirement. So the first case is no longer needed. The second case is added in both client_bulk_write_test.go and client_test.go.

@qingyang-hu qingyang-hu force-pushed the godriver2388v2 branch 2 times, most recently from 9958e3f to 82df60a Compare December 4, 2024 20:14
mtOpts := mtest.NewOptions().MinServerVersion("8.0").AtlasDataLake(false).ClientType(mtest.Pinned)
mt := mtest.New(t, mtOpts)

mt.Run("bulkWrite batch splits a writeModels input with greater than maxWriteBatchSize operations", func(mt *mtest.T) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we label the prose tests? I.e., this should be

3. bulkWrite batch splits a writeModels input with greater than maxWriteBatchSize operations

cli, err := mongo.Connect(cliOptions)
require.NoError(mt, err, "Connect error: %v", err)
_, err = cli.BulkWrite(context.Background(), models)
assert.ErrorContains(mt, err, "context deadline exceeded", "expected a timeout error, got: %v", err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest using asser.ErrorIs and the package error context.DeadlineExceeded:

Suggested change
assert.ErrorContains(mt, err, "context deadline exceeded", "expected a timeout error, got: %v", err)
assert.ErrorIs(mt, err, context.DeadlineExceeded, "expected a timeout error, got: %v", err)

if res == nil || !res.Acknowledged {
return newDocumentResult(emptyCoreDocument, err), nil
}
rawBuilder := bsoncore.NewDocumentBuilder().
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we use bsoncore? Can we just populate mongo.ClientBulkWriteResult and encode?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The encoder encodes all fields in lowercase by default. An alternative may be a struct with tags. The current resolution follows the pattern in executeCreateChangeStream and executeListDatabases.

model.ArrayFilters = v.ArrayFilters
}
return v.Namespace, model, nil

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

Hint *bson.RawValue
Upsert *bool
}
err := bson.Unmarshal(value, &v)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to define the extra fields? Can we unmarshal into an embedded mongo.ClientUpdateOneModel?

var v struct {
	Namespace string
	mongo.ClientUpdateOneModel
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The spec tests put bulk write fields in parallel with the namespace. We cannot embed mongo.ClientUpdateOneModel without a nested level.

prestonvasquez
prestonvasquez previously approved these changes Dec 21, 2024
Comment on lines 435 to 437
if doc.filter == nil {
return nil, fmt.Errorf("%w: filter is required", err)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to nest this nil filter check in this error handling block? Can we move this check to the beginning of marshal?

Optional: Consider a clearer error message, like

update filter cannot be nil

Comment on lines 300 to 302
if filter == nil {
return nil, fmt.Errorf("%w: filter is required", err)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to nest this nil filter check in this error handling block? Can we move this check to the beginning of marshal?

Optional: Consider a clearer error message, like

delete filter cannot be nil

mongo/errors.go Outdated
// A top-level error that occurred when attempting to communicate with the server
// or execute the bulk write. This value may not be populated if the exception was
// thrown due to errors occurring on individual writes.
TopLevelError *WriteError
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: Consider the more conventional Err or WriteError.

prestonvasquez
prestonvasquez previously approved these changes Jan 7, 2025
Copy link
Collaborator

@matthewdale matthewdale left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few requests for comments on confusing code, but everything else looks good.

@@ -2172,3 +2218,35 @@ func sessionsSupported(wireVersion *description.VersionRange) bool {
func retryWritesSupported(s description.Server) bool {
return s.SessionTimeoutMinutes != nil && s.Kind != description.ServerKindStandalone
}

func documentSequenceToArray(src []byte) (bsoncore.Array, []byte, bool) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was mistaken about the return type of this function in my previous comment. It seems that this function actually returns a bsoncore.Element, not a bsoncore.Array.

I strongly recommend adding a comment that describes the expected inputs and outputs for this function to reduce confusion.

cmd bsoncore.Document
requestID int32
cmdName string
docArray bsoncore.Array
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was mistaken about the type of this value in my previous comment. It seems that this is actually a byte slice containing one or many BSON array elements (i.e. multiple concatenated bsoncore.Element values), not a bsoncore.Array. Since there's not an analogous bsoncore type, I recommend making this a []byte. I also recommend adding a comment to describe the expected contents of the byte slice to reduce confusion.

Comment on lines 1413 to 1416
for b := dst[batchOffset:]; len(b) > 0; /* nothing */ {
var array bsoncore.Array
var ok bool
array, b, ok = documentSequenceToArray(b)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend adding a comment that describes what this block does, including the expected contents of b.

Comment on lines 226 to 233
cliOptions := options.Client().
SetTimeout(2 * time.Second).
SetMonitor(cm).
ApplyURI(mtest.ClusterURI())
integtest.AddTestServerAPIVersion(cliOptions)
cli, err := mongo.Connect(cliOptions)
require.NoError(mt, err, "Connect error: %v", err)
_, err = cli.BulkWrite(context.Background(), writes)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use mt.ResetClient instead.

Suggested change
cliOptions := options.Client().
SetTimeout(2 * time.Second).
SetMonitor(cm).
ApplyURI(mtest.ClusterURI())
integtest.AddTestServerAPIVersion(cliOptions)
cli, err := mongo.Connect(cliOptions)
require.NoError(mt, err, "Connect error: %v", err)
_, err = cli.BulkWrite(context.Background(), writes)
cliOptions := options.Client().
SetTimeout(2 * time.Second).
SetMonitor(cm)
mt.ResetClient(cliOptions)
_, err = mt.Client.BulkWrite(context.Background(), writes)

Comment on lines 430 to 432
dec := bson.NewDecoder(bson.NewDocumentReader(bytes.NewReader(resp)))
dec.SetRegistry(mb.client.registry)
err := dec.Decode(&res)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the user-defined registry is not necessary for decoding command documents (only for encoding/decoding user document data).

Suggested change
dec := bson.NewDecoder(bson.NewDocumentReader(bytes.NewReader(resp)))
dec.SetRegistry(mb.client.registry)
err := dec.Decode(&res)
err := bson.Unmarshal(resp, &res)

Copy link
Collaborator

@matthewdale matthewdale left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! 👍

@qingyang-hu qingyang-hu merged commit 50cf0c2 into mongodb:master Jan 24, 2025
29 of 35 checks passed
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
priority-2-medium Medium Priority PR for Review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants