Skip to content

Commit d106138

Browse files
committed
Merge pull request #410
2 parents 5731a02 + 202bef6 commit d106138

File tree

6 files changed

+262
-3
lines changed

6 files changed

+262
-3
lines changed

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

Lines changed: 81 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
@@ -93,6 +106,39 @@ source:
93106
ref: readPreference
94107
---
95108
arg_name: option
109+
name: max
110+
type: array|object
111+
description: |
112+
The exclusive upper bound for a specific index.
113+
114+
.. versionadded:: 1.2
115+
interface: phpmethod
116+
operation: ~
117+
optional: true
118+
---
119+
arg_name: option
120+
name: maxScan
121+
type: integer
122+
description: |
123+
Maximum number of documents or index keys to scan when executing the query.
124+
125+
.. versionadded:: 1.2
126+
interface: phpmethod
127+
operation: ~
128+
optional: true
129+
---
130+
arg_name: option
131+
name: min
132+
type: array|object
133+
description: |
134+
The inclusive lower bound for a specific index.
135+
136+
.. versionadded:: 1.2
137+
interface: phpmethod
138+
operation: ~
139+
optional: true
140+
---
141+
arg_name: option
96142
name: oplogReplay
97143
type: boolean
98144
description: |
@@ -120,6 +166,41 @@ operation: ~
120166
optional: true
121167
---
122168
arg_name: option
169+
name: returnKey
170+
type: boolean
171+
description: |
172+
If true, returns only the index keys in the resulting documents.
173+
174+
.. versionadded:: 1.2
175+
interface: phpmethod
176+
operation: ~
177+
optional: true
178+
---
179+
arg_name: option
180+
name: showRecordId
181+
type: boolean
182+
description: |
183+
Determines whether to return the record identifier for each document. If true,
184+
adds a field $recordId to the returned documents.
185+
186+
.. versionadded:: 1.2
187+
interface: phpmethod
188+
operation: ~
189+
optional: true
190+
---
191+
arg_name: option
192+
name: snapshot
193+
type: boolean
194+
description: |
195+
Prevents the cursor from returning a document more than once because of an
196+
intervening write operation.
197+
198+
.. versionadded:: 1.2
199+
interface: phpmethod
200+
operation: ~
201+
optional: true
202+
---
203+
arg_name: option
123204
name: allowPartialResults
124205
type: boolean
125206
description: |

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

Lines changed: 24 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
@@ -36,6 +40,26 @@ source:
3640
post: |
3741
This will be used for the returned result document.
3842
---
43+
source:
44+
file: apiargs-MongoDBCollection-method-find-option.yaml
45+
ref: max
46+
---
47+
source:
48+
file: apiargs-MongoDBCollection-method-find-option.yaml
49+
ref: maxScan
50+
---
51+
source:
52+
file: apiargs-MongoDBCollection-method-find-option.yaml
53+
ref: min
54+
---
55+
source:
56+
file: apiargs-MongoDBCollection-method-find-option.yaml
57+
ref: returnKey
58+
---
59+
source:
60+
file: apiargs-MongoDBCollection-method-find-option.yaml
61+
ref: showRecordId
62+
---
3963
source:
4064
file: apiargs-MongoDBCollection-method-find-option.yaml
4165
ref: modifiers

src/Operation/Find.php

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,23 @@ 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
*
79+
* * max (document): The exclusive upper bound for a specific index.
80+
*
81+
* * maxScan (integer): Maximum number of documents or index keys to scan
82+
* when executing the query.
83+
*
7584
* * maxTimeMS (integer): The maximum amount of time to allow the query to
7685
* run. If "$maxTimeMS" also exists in the modifiers document, this
7786
* option will take precedence.
7887
*
88+
* * min (document): The inclusive upper bound for a specific index.
89+
*
7990
* * modifiers (document): Meta operators that modify the output or
8091
* behavior of a query. Use of these operators is deprecated in favor of
8192
* named options.
@@ -97,8 +108,18 @@ class Find implements Executable
97108
*
98109
* * readPreference (MongoDB\Driver\ReadPreference): Read preference.
99110
*
111+
* * returnKey (boolean): If true, returns only the index keys in the
112+
* resulting documents.
113+
*
114+
* * showRecordId (boolean): Determines whether to return the record
115+
* identifier for each document. If true, adds a field $recordId to the
116+
* returned documents.
117+
*
100118
* * skip (integer): The number of documents to skip before returning.
101119
*
120+
* * snapshot (boolean): Prevents the cursor from returning a document more
121+
* than once because of an intervening write operation.
122+
*
102123
* * sort (document): The order in which to return matching documents. If
103124
* "$orderby" also exists in the modifiers document, this option will
104125
* take precedence.
@@ -146,14 +167,30 @@ public function __construct($databaseName, $collectionName, $filter, array $opti
146167
}
147168
}
148169

170+
if (isset($options['hint']) && ! is_string($options['hint']) && ! is_array($options['hint']) && ! is_object($options['hint'])) {
171+
throw InvalidArgumentException::invalidType('"hint" option', $options['hint'], 'string or array or object');
172+
}
173+
149174
if (isset($options['limit']) && ! is_integer($options['limit'])) {
150175
throw InvalidArgumentException::invalidType('"limit" option', $options['limit'], 'integer');
151176
}
152177

178+
if (isset($options['max']) && ! is_array($options['max']) && ! is_object($options['max'])) {
179+
throw InvalidArgumentException::invalidType('"max" option', $options['max'], 'array or object');
180+
}
181+
182+
if (isset($options['maxScan']) && ! is_integer($options['maxScan'])) {
183+
throw InvalidArgumentException::invalidType('"maxScan" option', $options['maxScan'], 'integer');
184+
}
185+
153186
if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) {
154187
throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer');
155188
}
156189

190+
if (isset($options['min']) && ! is_array($options['min']) && ! is_object($options['min'])) {
191+
throw InvalidArgumentException::invalidType('"min" option', $options['min'], 'array or object');
192+
}
193+
157194
if (isset($options['modifiers']) && ! is_array($options['modifiers']) && ! is_object($options['modifiers'])) {
158195
throw InvalidArgumentException::invalidType('"modifiers" option', $options['modifiers'], 'array or object');
159196
}
@@ -178,10 +215,22 @@ public function __construct($databaseName, $collectionName, $filter, array $opti
178215
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference');
179216
}
180217

218+
if (isset($options['returnKey']) && ! is_bool($options['returnKey'])) {
219+
throw InvalidArgumentException::invalidType('"returnKey" option', $options['returnKey'], 'boolean');
220+
}
221+
222+
if (isset($options['showRecordId']) && ! is_bool($options['showRecordId'])) {
223+
throw InvalidArgumentException::invalidType('"showRecordId" option', $options['showRecordId'], 'boolean');
224+
}
225+
181226
if (isset($options['skip']) && ! is_integer($options['skip'])) {
182227
throw InvalidArgumentException::invalidType('"skip" option', $options['skip'], 'integer');
183228
}
184229

230+
if (isset($options['snapshot']) && ! is_bool($options['snapshot'])) {
231+
throw InvalidArgumentException::invalidType('"snapshot" option', $options['snapshot'], 'boolean');
232+
}
233+
185234
if (isset($options['sort']) && ! is_array($options['sort']) && ! is_object($options['sort'])) {
186235
throw InvalidArgumentException::invalidType('"sort" option', $options['sort'], 'array or object');
187236
}
@@ -249,14 +298,16 @@ private function createQuery()
249298
}
250299
}
251300

252-
foreach (['allowPartialResults', 'batchSize', 'comment', 'limit', 'maxTimeMS', 'noCursorTimeout', 'oplogReplay', 'projection', 'readConcern', 'skip', 'sort'] as $option) {
301+
foreach (['allowPartialResults', 'batchSize', 'comment', 'hint', 'limit', 'maxScan', 'maxTimeMS', 'noCursorTimeout', 'oplogReplay', 'projection', 'readConcern', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'] as $option) {
253302
if (isset($this->options[$option])) {
254303
$options[$option] = $this->options[$option];
255304
}
256305
}
257306

258-
if (isset($this->options['collation'])) {
259-
$options['collation'] = (object) $this->options['collation'];
307+
foreach (['collation', 'max', 'min'] as $option) {
308+
if (isset($this->options[$option])) {
309+
$options[$option] = (object) $this->options[$option];
310+
}
260311
}
261312

262313
$modifiers = empty($this->options['modifiers']) ? [] : (array) $this->options['modifiers'];

src/Operation/FindOne.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,21 @@ 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+
*
55+
* * max (document): The exclusive upper bound for a specific index.
56+
*
57+
* * maxScan (integer): Maximum number of documents or index keys to scan
58+
* when executing the query.
59+
*
5160
* * maxTimeMS (integer): The maximum amount of time to allow the query to
5261
* run. If "$maxTimeMS" also exists in the modifiers document, this
5362
* option will take precedence.
5463
*
64+
* * min (document): The inclusive upper bound for a specific index.
65+
*
5566
* * modifiers (document): Meta-operators modifying the output or behavior
5667
* of a query.
5768
*
@@ -65,6 +76,13 @@ class FindOne implements Executable
6576
*
6677
* * readPreference (MongoDB\Driver\ReadPreference): Read preference.
6778
*
79+
* * returnKey (boolean): If true, returns only the index keys in the
80+
* resulting documents.
81+
*
82+
* * showRecordId (boolean): Determines whether to return the record
83+
* identifier for each document. If true, adds a field $recordId to the
84+
* returned documents.
85+
*
6886
* * skip (integer): The number of documents to skip before returning.
6987
*
7088
* * sort (document): The order in which to return matching documents. If

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
*/

0 commit comments

Comments
 (0)