Skip to content

Commit 71d0f6f

Browse files
committed
Fix support for subqueries using the query builder
1 parent 7c1d0ab commit 71d0f6f

File tree

4 files changed

+76
-13
lines changed

4 files changed

+76
-13
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
# Changelog
22
All notable changes to this project will be documented in this file.
33

4+
## [4.1.2]
45

5-
## [4.1.1]
6+
* Fix support for subqueries using the query builder by @GromNaN in [#2717](https://github.com/mongodb/laravel-mongodb/pull/2717)
7+
8+
## [4.1.1] - 2024-01-17
69

710
* Fix casting issues by [@stubbo](https://github.com/stubbo) in [#2705](https://github.com/mongodb/laravel-mongodb/pull/2705)
811
* Move documentation to the mongodb.com domain at [https://www.mongodb.com/docs/drivers/php/laravel-mongodb/current/](https://www.mongodb.com/docs/drivers/php/laravel-mongodb/current/)

docs/query-builder.txt

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Query Builder
1313

1414
The database driver plugs right into the original query builder.
1515

16-
When using MongoDB connections, you will be able to build fluent queries to
16+
When using MongoDB connections, you will be able to build fluent queries to
1717
perform database operations.
1818

1919
For your convenience, there is a ``collection`` alias for ``table`` and
@@ -85,7 +85,7 @@ Available operations
8585

8686
$users = User::whereIn('age', [16, 18, 20])->get();
8787

88-
When using ``whereNotIn`` objects will be returned if the field is
88+
When using ``whereNotIn`` objects will be returned if the field is
8989
non-existent. Combine with ``whereNotNull('age')`` to omit those documents.
9090

9191
**whereBetween**
@@ -137,7 +137,7 @@ The usage is the same as ``whereMonth`` / ``whereDay`` / ``whereYear`` / ``where
137137

138138
**groupBy**
139139

140-
Selected columns that are not grouped will be aggregated with the ``$last``
140+
Selected columns that are not grouped will be aggregated with the ``$last``
141141
function.
142142

143143
.. code-block:: php
@@ -230,7 +230,7 @@ You may also specify more columns to update:
230230
MongoDB-specific operators
231231
~~~~~~~~~~~~~~~~~~~~~~~~~~
232232

233-
In addition to the Laravel Eloquent operators, all available MongoDB query
233+
In addition to the Laravel Eloquent operators, all available MongoDB query
234234
operators can be used with ``where``:
235235

236236
.. code-block:: php
@@ -279,7 +279,7 @@ Selects documents where values match a specified regular expression.
279279

280280
.. note::
281281

282-
You can also use the Laravel regexp operations. These will automatically
282+
You can also use the Laravel regexp operations. These will automatically
283283
convert your regular expression string to a ``MongoDB\BSON\Regex`` object.
284284

285285
.. code-block:: php
@@ -292,9 +292,37 @@ The inverse of regexp:
292292

293293
User::where('name', 'not regexp', '/.*doe/i')->get();
294294

295+
**ElemMatch**
296+
297+
The :manual:`$elemMatch </reference/operator/query/elemMatch//>` operator
298+
matches documents that contain an array field with at least one element that
299+
matches all the specified query criteria.
300+
301+
The following query matches only those documents where the results array
302+
contains at least one element that is both greater than or equal to 80 and
303+
is less than 85:
304+
305+
.. code-block:: php
306+
307+
User::where('results', 'elemMatch', ['gte' => 80, 'lt' => 85])->get();
308+
309+
A closure can be used to create more complex sub-queries.
310+
311+
The following query matches only those documents where the results array
312+
contains at least one element with both product equal to "xyz" and score
313+
greater than or equal to 8:
314+
315+
.. code-block:: php
316+
317+
User::where('results', 'elemMatch', function (Builder $builder) {
318+
$builder
319+
->where('product', 'xyz')
320+
->andWhere('score', '>', 50);
321+
})->get();
322+
295323
**Type**
296324

297-
Selects documents if a field is of the specified type. For more information
325+
Selects documents if a field is of the specified type. For more information
298326
check: :manual:`$type </reference/operator/query/type/#op._S_type/>` in the
299327
MongoDB Server documentation.
300328

@@ -304,7 +332,7 @@ MongoDB Server documentation.
304332

305333
**Mod**
306334

307-
Performs a modulo operation on the value of a field and selects documents with
335+
Performs a modulo operation on the value of a field and selects documents with
308336
a specified result.
309337

310338
.. code-block:: php
@@ -366,10 +394,10 @@ MongoDB-specific Geo operations
366394
You can make a ``geoNear`` query on MongoDB.
367395
You can omit specifying the automatic fields on the model.
368396
The returned instance is a collection, so you can call the `Collection <https://laravel.com/docs/9.x/collections>`__ operations.
369-
Make sure that your model has a ``location`` field, and a
397+
Make sure that your model has a ``location`` field, and a
370398
`2ndSphereIndex <https://www.mongodb.com/docs/manual/core/2dsphere>`__.
371399
The data in the ``location`` field must be saved as `GeoJSON <https://www.mongodb.com/docs/manual/reference/geojson/>`__.
372-
The ``location`` points must be saved as `WGS84 <https://www.mongodb.com/docs/manual/reference/glossary/#std-term-WGS84>`__
400+
The ``location`` points must be saved as `WGS84 <https://www.mongodb.com/docs/manual/reference/glossary/#std-term-WGS84>`__
373401
reference system for geometry calculation. That means that you must
374402
save ``longitude and latitude``, in that order specifically, and to find near
375403
with calculated distance, you ``must do the same way``.
@@ -405,7 +433,7 @@ with calculated distance, you ``must do the same way``.
405433
Inserts, updates and deletes
406434
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
407435

408-
Inserting, updating and deleting records works just like the original Eloquent.
436+
Inserting, updating and deleting records works just like the original Eloquent.
409437
Please check `Laravel Docs' Eloquent section <https://laravel.com/docs/6.x/eloquent>`__.
410438

411439
Here, only the MongoDB-specific operations are specified.
@@ -431,14 +459,14 @@ These expressions will be injected directly into the query.
431459
'$where' => '/.*123.*/.test(this["hyphenated-field"])',
432460
])->get();
433461

434-
You can also perform raw expressions on the internal MongoCollection object.
462+
You can also perform raw expressions on the internal MongoCollection object.
435463
If this is executed on the model class, it will return a collection of models.
436464

437465
If this is executed on the query builder, it will return the original response.
438466

439467
**Cursor timeout**
440468

441-
To prevent ``MongoCursorTimeout`` exceptions, you can manually set a timeout
469+
To prevent ``MongoCursorTimeout`` exceptions, you can manually set a timeout
442470
value that will be applied to the cursor:
443471

444472
.. code-block:: php

src/Query/Builder.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,6 +1363,13 @@ protected function compileWhereRaw(array $where): mixed
13631363
return $where['sql'];
13641364
}
13651365

1366+
protected function compileWhereSub(array $where): mixed
1367+
{
1368+
$where['value'] = $where['query']->compileWheres();
1369+
1370+
return $this->compileWhereBasic($where);
1371+
}
1372+
13661373
/**
13671374
* Set custom options for the query.
13681375
*

tests/Query/BuilderTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,6 +1127,31 @@ function (Builder $builder) {
11271127
],
11281128
fn (Builder $builder) => $builder->groupBy('foo'),
11291129
];
1130+
1131+
yield 'sub-query' => [
1132+
[
1133+
'find' => [
1134+
[
1135+
'filters' => [
1136+
'$elemMatch' => [
1137+
'$and' => [
1138+
['search_by' => 'by search'],
1139+
['value' => 'foo'],
1140+
],
1141+
],
1142+
],
1143+
],
1144+
[], // options
1145+
],
1146+
],
1147+
fn (Builder $builder) => $builder->where(
1148+
'filters',
1149+
'elemMatch',
1150+
function (Builder $elemMatchQuery): void {
1151+
$elemMatchQuery->where([ 'search_by' => 'by search', 'value' => 'foo' ]);
1152+
},
1153+
),
1154+
];
11301155
}
11311156

11321157
/** @dataProvider provideExceptions */

0 commit comments

Comments
 (0)