Skip to content

Commit d960f5f

Browse files
committed
PHPLIB-286: Support hint option for Find and FindOne
1 parent 5731a02 commit d960f5f

File tree

6 files changed

+91
-1
lines changed

6 files changed

+91
-1
lines changed

docs/includes/apiargs-MongoDBCollection-method-find-option.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,19 @@ interface: phpmethod
8080
operation: ~
8181
optional: true
8282
---
83+
arg_name: option
84+
name: hint
85+
type: string|array|object
86+
description: |
87+
The index to use. Specify either the index name as a string or the index key
88+
pattern as a document. If specified, then the query system will only consider
89+
plans using the hinted index.
90+
91+
.. versionadded:: 1.2
92+
interface: phpmethod
93+
operation: ~
94+
optional: true
95+
---
8396
source:
8497
file: apiargs-common-option.yaml
8598
ref: maxTimeMS

docs/includes/apiargs-MongoDBCollection-method-findOne-option.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ source:
1818
file: apiargs-MongoDBCollection-method-find-option.yaml
1919
ref: comment
2020
---
21+
source:
22+
file: apiargs-MongoDBCollection-method-find-option.yaml
23+
ref: hint
24+
---
2125
source:
2226
file: apiargs-common-option.yaml
2327
ref: maxTimeMS

src/Operation/Find.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ class Find implements Executable
7070
* NON_TAILABLE, TAILABLE, or TAILABLE_AWAIT. The default is
7171
* NON_TAILABLE.
7272
*
73+
* * hint (string|document): The index to use. Specify either the index
74+
* name as a string or the index key pattern as a document. If specified,
75+
* then the query system will only consider plans using the hinted index.
76+
*
7377
* * limit (integer): The maximum number of documents to return.
7478
*
7579
* * maxTimeMS (integer): The maximum amount of time to allow the query to
@@ -146,6 +150,10 @@ public function __construct($databaseName, $collectionName, $filter, array $opti
146150
}
147151
}
148152

153+
if (isset($options['hint']) && ! is_string($options['hint']) && ! is_array($options['hint']) && ! is_object($options['hint'])) {
154+
throw InvalidArgumentException::invalidType('"hint" option', $options['hint'], 'string or array or object');
155+
}
156+
149157
if (isset($options['limit']) && ! is_integer($options['limit'])) {
150158
throw InvalidArgumentException::invalidType('"limit" option', $options['limit'], 'integer');
151159
}
@@ -249,7 +257,7 @@ private function createQuery()
249257
}
250258
}
251259

252-
foreach (['allowPartialResults', 'batchSize', 'comment', 'limit', 'maxTimeMS', 'noCursorTimeout', 'oplogReplay', 'projection', 'readConcern', 'skip', 'sort'] as $option) {
260+
foreach (['allowPartialResults', 'batchSize', 'comment', 'hint', 'limit', 'maxTimeMS', 'noCursorTimeout', 'oplogReplay', 'projection', 'readConcern', 'skip', 'sort'] as $option) {
253261
if (isset($this->options[$option])) {
254262
$options[$option] = $this->options[$option];
255263
}

src/Operation/FindOne.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ class FindOne implements Executable
4848
* * comment (string): Attaches a comment to the query. If "$comment" also
4949
* exists in the modifiers document, this option will take precedence.
5050
*
51+
* * hint (string|document): The index to use. Specify either the index
52+
* name as a string or the index key pattern as a document. If specified,
53+
* then the query system will only consider plans using the hinted index.
54+
*
5155
* * maxTimeMS (integer): The maximum amount of time to allow the query to
5256
* run. If "$maxTimeMS" also exists in the modifiers document, this
5357
* option will take precedence.

tests/Operation/FindFunctionalTest.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace MongoDB\Tests\Operation;
44

55
use MongoDB\Driver\BulkWrite;
6+
use MongoDB\Operation\CreateIndexes;
67
use MongoDB\Operation\Find;
78
use MongoDB\Tests\CommandObserver;
89
use stdClass;
@@ -28,6 +29,57 @@ function(stdClass $command) {
2829
);
2930
}
3031

32+
public function testHintOption()
33+
{
34+
$bulkWrite = new BulkWrite;
35+
$bulkWrite->insert(['_id' => 1, 'x' => 1]);
36+
$bulkWrite->insert(['_id' => 2, 'x' => 2]);
37+
$bulkWrite->insert(['_id' => 3, 'y' => 3]);
38+
$this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite);
39+
40+
$createIndexes = new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), [
41+
['key' => ['x' => 1], 'sparse' => true, 'name' => 'sparse_x'],
42+
['key' => ['y' => 1]],
43+
]);
44+
$createIndexes->execute($this->getPrimaryServer());
45+
46+
$hintsUsingSparseIndex = [
47+
['x' => 1],
48+
'sparse_x',
49+
];
50+
51+
foreach ($hintsUsingSparseIndex as $hint) {
52+
$operation = new Find($this->getDatabaseName(), $this->getCollectionName(), [], ['hint' => $hint]);
53+
$cursor = $operation->execute($this->getPrimaryServer());
54+
55+
$expectedDocuments = [
56+
(object) ['_id' => 1, 'x' => 1],
57+
(object) ['_id' => 2, 'x' => 2],
58+
];
59+
60+
$this->assertEquals($expectedDocuments, $cursor->toArray());
61+
}
62+
63+
$hintsNotUsingSparseIndex = [
64+
['_id' => 1],
65+
['y' => 1],
66+
'y_1',
67+
];
68+
69+
foreach ($hintsNotUsingSparseIndex as $hint) {
70+
$operation = new Find($this->getDatabaseName(), $this->getCollectionName(), [], ['hint' => $hint]);
71+
$cursor = $operation->execute($this->getPrimaryServer());
72+
73+
$expectedDocuments = [
74+
(object) ['_id' => 1, 'x' => 1],
75+
(object) ['_id' => 2, 'x' => 2],
76+
(object) ['_id' => 3, 'y' => 3],
77+
];
78+
79+
$this->assertEquals($expectedDocuments, $cursor->toArray());
80+
}
81+
}
82+
3183
/**
3284
* @dataProvider provideTypeMapOptionsAndExpectedDocuments
3385
*/

tests/Operation/FindTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ public function provideInvalidConstructorOptions()
4848
$options[][] = ['cursorType' => $value];
4949
}
5050

51+
foreach ($this->getInvalidHintValues() as $value) {
52+
$options[][] = ['hint' => $value];
53+
}
54+
5155
foreach ($this->getInvalidIntegerValues() as $value) {
5256
$options[][] = ['limit' => $value];
5357
}
@@ -91,6 +95,11 @@ public function provideInvalidConstructorOptions()
9195
return $options;
9296
}
9397

98+
private function getInvalidHintValues()
99+
{
100+
return [123, 3.14, true];
101+
}
102+
94103
/**
95104
* @expectedException MongoDB\Exception\InvalidArgumentException
96105
* @dataProvider provideInvalidConstructorCursorTypeOptions

0 commit comments

Comments
 (0)