Skip to content

Commit

Permalink
GODRIVER-3412 Add index hint support for distinct command. (#1888)
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewdale authored Nov 15, 2024
1 parent a74791f commit 27ee659
Show file tree
Hide file tree
Showing 6 changed files with 257 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,8 @@ func executeDistinct(ctx context.Context, operation *operation) (*operationResul
val := elem.Value()

switch key {
case "hint":
opts.SetHint(val)
case "collation":
collation, err := createCollation(val.Document())
if err != nil {
Expand Down
10 changes: 10 additions & 0 deletions mongo/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -1281,6 +1281,16 @@ func (coll *Collection) Distinct(
}
op.Comment(comment)
}
if args.Hint != nil {
if isUnorderedMap(args.Hint) {
return &DistinctResult{err: ErrMapForOrderedArgument{"hint"}}
}
hint, err := marshalValue(args.Hint, coll.bsonOpts, coll.registry)
if err != nil {
return &DistinctResult{err: err}
}
op.Hint(hint)
}
retry := driver.RetryNone
if coll.client.retryReads {
retry = driver.RetryOncePerCommand
Expand Down
19 changes: 19 additions & 0 deletions mongo/options/distinctoptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ package options
type DistinctOptions struct {
Collation *Collation
Comment interface{}
Hint interface{}
}

// DistinctOptionsBuilder contains options to configure distinct operations. Each
Expand Down Expand Up @@ -60,3 +61,21 @@ func (do *DistinctOptionsBuilder) SetComment(comment interface{}) *DistinctOptio

return do
}

// SetHint specifies the index to use for the operation. This should either be
// the index name as a string or the index specification as a document. This
// option is only valid for MongoDB versions >= 7.1. Previous server versions
// will return an error if an index hint is specified. Distinct returns an error
// if the hint parameter is a multi-key map. The default value is nil, which
// means that no index hint will be sent.
//
// SetHint sets the Hint field.
func (do *DistinctOptionsBuilder) SetHint(hint interface{}) *DistinctOptionsBuilder {
do.Opts = append(do.Opts, func(opts *DistinctOptions) error {
opts.Hint = hint

return nil
})

return do
}
139 changes: 139 additions & 0 deletions testdata/crud/unified/distinct-hint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
{
"description": "distinct-hint",
"schemaVersion": "1.0",
"runOnRequirements": [
{
"minServerVersion": "7.1.0"
}
],
"createEntities": [
{
"client": {
"id": "client0",
"observeEvents": [
"commandStartedEvent"
]
}
},
{
"database": {
"id": "database0",
"client": "client0",
"databaseName": "distinct-hint-tests"
}
},
{
"collection": {
"id": "collection0",
"database": "database0",
"collectionName": "coll0"
}
}
],
"initialData": [
{
"collectionName": "coll0",
"databaseName": "distinct-hint-tests",
"documents": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 33
}
]
}
],
"tests": [
{
"description": "distinct with hint string",
"operations": [
{
"name": "distinct",
"object": "collection0",
"arguments": {
"fieldName": "x",
"filter": {
"_id": 1
},
"hint": "_id_"
},
"expectResult": [
11
]
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"distinct": "coll0",
"key": "x",
"query": {
"_id": 1
},
"hint": "_id_"
},
"commandName": "distinct",
"databaseName": "distinct-hint-tests"
}
}
]
}
]
},
{
"description": "distinct with hint document",
"operations": [
{
"name": "distinct",
"object": "collection0",
"arguments": {
"fieldName": "x",
"filter": {
"_id": 1
},
"hint": {
"_id": 1
}
},
"expectResult": [
11
]
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"distinct": "coll0",
"key": "x",
"query": {
"_id": 1
},
"hint": {
"_id": 1
}
},
"commandName": "distinct",
"databaseName": "distinct-hint-tests"
}
}
]
}
]
}
]
}
73 changes: 73 additions & 0 deletions testdata/crud/unified/distinct-hint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
description: "distinct-hint"

schemaVersion: "1.0"
runOnRequirements:
# https://jira.mongodb.org/browse/SERVER-14227
# Server supports distinct with hint starting from 7.1.0.
- minServerVersion: "7.1.0"

createEntities:
- client:
id: &client0 client0
observeEvents: [ commandStartedEvent ]
- database:
id: &database0 database0
client: *client0
databaseName: &database0Name distinct-hint-tests
- collection:
id: &collection0 collection0
database: *database0
collectionName: &collection0Name coll0

initialData:
- collectionName: *collection0Name
databaseName: *database0Name
documents:
- { _id: 1, x: 11 }
- { _id: 2, x: 22 }
- { _id: 3, x: 33 }

tests:
- description: "distinct with hint string"
operations:
- name: distinct
object: *collection0
arguments:
fieldName: &fieldName x
filter: &filter { _id: 1 }
hint: _id_
expectResult: [ 11 ]
expectEvents:
- client: *client0
events:
- commandStartedEvent:
command:
distinct: *collection0Name
key: *fieldName
query: *filter
hint: _id_
commandName: distinct
databaseName: *database0Name

- description: "distinct with hint document"
operations:
- name: distinct
object: *collection0
arguments:
fieldName: *fieldName
filter: *filter
hint:
_id: 1
expectResult: [ 11 ]
expectEvents:
- client: *client0
events:
- commandStartedEvent:
command:
distinct: *collection0Name
key: *fieldName
query: *filter
hint:
_id: 1
commandName: distinct
databaseName: *database0Name
14 changes: 14 additions & 0 deletions x/mongo/driver/operation/distinct.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type Distinct struct {
clock *session.ClusterClock
collection string
comment bsoncore.Value
hint bsoncore.Value
monitor *event.CommandMonitor
crypt driver.Crypt
database string
Expand Down Expand Up @@ -120,6 +121,9 @@ func (d *Distinct) command(dst []byte, desc description.SelectedServer) ([]byte,
if d.comment.Type != bsoncore.Type(0) {
dst = bsoncore.AppendValueElement(dst, "comment", d.comment)
}
if d.hint.Type != bsoncore.Type(0) {
dst = bsoncore.AppendValueElement(dst, "hint", d.hint)
}
if d.key != nil {
dst = bsoncore.AppendStringElement(dst, "key", *d.key)
}
Expand Down Expand Up @@ -199,6 +203,16 @@ func (d *Distinct) Comment(comment bsoncore.Value) *Distinct {
return d
}

// Hint sets a value to help trace an operation.
func (d *Distinct) Hint(hint bsoncore.Value) *Distinct {
if d == nil {
d = new(Distinct)
}

d.hint = hint
return d
}

// CommandMonitor sets the monitor to use for APM events.
func (d *Distinct) CommandMonitor(monitor *event.CommandMonitor) *Distinct {
if d == nil {
Expand Down

0 comments on commit 27ee659

Please sign in to comment.