@@ -33,6 +33,20 @@ class Builder extends QueryBuilder {
33
33
*/
34
34
public $ timeout ;
35
35
36
+ /**
37
+ * Flag for use aggregation
38
+ *
39
+ * @var bool
40
+ */
41
+ protected $ useAggregation = false ;
42
+
43
+ /**
44
+ * Paginate columns
45
+ *
46
+ * @var array
47
+ */
48
+ protected $ paginateCols = [];
49
+
36
50
/**
37
51
* All of the available clause operators.
38
52
*
@@ -143,9 +157,11 @@ public function getFresh($columns = array())
143
157
$ wheres = $ this ->compileWheres ();
144
158
145
159
// Use MongoDB's aggregation framework when using grouping or aggregation functions.
146
- if ($ this ->groups or $ this ->aggregate )
160
+ if ($ this ->groups or $ this ->aggregate or $ this -> useAggregation )
147
161
{
148
162
$ group = array ();
163
+ $ project = array ();
164
+ $ projectEndColumns = array ();
149
165
150
166
// Add grouping columns to the $group part of the aggregation pipeline.
151
167
if ($ this ->groups )
@@ -159,17 +175,12 @@ public function getFresh($columns = array())
159
175
$ group [$ column ] = array ('$last ' => '$ ' . $ column );
160
176
}
161
177
}
162
- else
163
- {
164
- // If we don't use grouping, set the _id to null to prepare the pipeline for
165
- // other aggregation functions.
166
- $ group ['_id ' ] = null ;
167
- }
168
178
169
179
// Add aggregation functions to the $group part of the aggregation pipeline,
170
180
// these may override previous aggregations.
171
181
if ($ this ->aggregate )
172
182
{
183
+
173
184
$ function = $ this ->aggregate ['function ' ];
174
185
175
186
foreach ($ this ->aggregate ['columns ' ] as $ column )
@@ -187,25 +198,81 @@ public function getFresh($columns = array())
187
198
}
188
199
}
189
200
190
- // If no aggregation functions are used, we add the additional select columns
191
- // to the pipeline here, aggregating them by $last.
201
+
192
202
else
193
203
{
204
+
205
+ // If no aggregation functions are used, we add the additional select columns
206
+ // to the pipeline here, aggregating them by $last.
194
207
foreach ($ this ->columns as $ column )
195
208
{
196
- $ key = str_replace ('. ' , '_ ' , $ column );
209
+ if (!in_array ($ column , $ this ->paginateCols ) ) {
210
+ $ key = str_replace ('. ' , '_ ' , $ column );
197
211
198
- $ group [$ key ] = array ('$last ' => '$ ' . $ column );
212
+ $ group [$ key ] = array ('$last ' => '$ ' . $ column );
213
+ }
199
214
}
215
+
216
+
217
+ //add cols to filter groups and use mongoDb map/reduce
218
+ if ($ this ->columns ) {
219
+
220
+ if ($ this ->columns || $ this ->groups ) {
221
+ $ cols = array_merge ((array )$ this ->columns , (array )$ this ->groups );
222
+ foreach ($ cols as $ column ) {
223
+ $ key = str_replace ('. ' , '_ ' , $ column );
224
+ $ project [$ key ] = 1 ;
225
+ }
226
+ }
227
+
228
+ if ($ this ->columns ) {
229
+ foreach ($ cols as $ column ) {
230
+ $ key = str_replace ('. ' , '_ ' , $ column );
231
+ $ projectEndColumns [$ key ] = 1 ;
232
+ }
233
+ }
234
+ }
235
+
200
236
}
201
237
238
+
202
239
// Build the aggregation pipeline.
203
240
$ pipeline = array ();
204
241
if ($ wheres ) $ pipeline [] = array ('$match ' => $ wheres );
205
- $ pipeline [] = array ('$group ' => $ group );
242
+
243
+
244
+ //filter used columns
245
+ if (!empty ($ project )) {
246
+ $ pipeline [] = array ('$project ' => $ project );
247
+ }
248
+
249
+ if (!empty ($ group )) {
250
+ if (!isset ($ group ['_id ' ])) {
251
+ // If we don't use grouping, set the _id to null to prepare the pipeline for
252
+ // other aggregation functions.
253
+ $ group ['_id ' ] = null ;
254
+ }
255
+
256
+ $ pipeline [] = array ('$group ' => $ group );
257
+ }
258
+
259
+ //filter columns
260
+ if (!empty ($ projectEndColumns )) {
261
+ $ pipeline [] = array ('$project ' => $ projectEndColumns );
262
+ }
263
+
264
+
265
+
206
266
207
267
// Apply order and limit
208
- if ($ this ->orders ) $ pipeline [] = array ('$sort ' => $ this ->orders );
268
+ if ($ this ->orders ) {
269
+ if (isset ($ this ->orders ['$natural ' ])) {
270
+ unset($ this ->orders ['$natural ' ]);
271
+ }
272
+ if (!empty ($ this ->orders )) {
273
+ $ pipeline [] = array ('$sort ' => $ this ->orders );
274
+ }
275
+ }
209
276
if ($ this ->offset ) $ pipeline [] = array ('$skip ' => $ this ->offset );
210
277
if ($ this ->limit ) $ pipeline [] = array ('$limit ' => $ this ->limit );
211
278
if ($ this ->projections ) $ pipeline [] = array ('$project ' => $ this ->projections );
@@ -302,7 +369,6 @@ public function aggregate($function, $columns = array())
302
369
if (isset ($ results [0 ]))
303
370
{
304
371
$ result = (array ) $ results [0 ];
305
-
306
372
return $ result ['aggregate ' ];
307
373
}
308
374
}
@@ -344,9 +410,54 @@ public function orderBy($column, $direction = 'asc')
344
410
$ this ->orders [$ column ] = $ direction ;
345
411
}
346
412
413
+ $ this ->useAggregation = true ;
414
+
347
415
return $ this ;
348
416
}
349
417
418
+ /**
419
+ * Set the "limit" value of the query.
420
+ *
421
+ * @param int $value
422
+ * @return $this
423
+ */
424
+ public function limit ($ value )
425
+ {
426
+ $ this ->useAggregation = true ;
427
+
428
+ return parent ::limit ((int )$ value );
429
+ }
430
+
431
+ /**
432
+ * Set the "offset" value of the query.
433
+ *
434
+ * @param int $value
435
+ * @return $this
436
+ */
437
+ public function offset ($ value )
438
+ {
439
+ $ this ->useAggregation = true ;
440
+
441
+ return parent ::offset ((int )$ value );
442
+ }
443
+
444
+
445
+ public function paginate ($ perPage = 15 , $ columns = array ('* ' )) {
446
+
447
+ $ this ->addPaginateCols ($ columns );
448
+ return parent ::paginate ($ perPage , $ columns );
449
+ }
450
+
451
+ public function addPaginateCols ($ columns )
452
+ {
453
+ if (in_array ('* ' , $ columns )) {
454
+ unset($ columns [array_search ('* ' , $ columns )]);
455
+ }
456
+ $ this ->paginateCols = $ this ->paginateCols +$ columns ;
457
+ }
458
+
459
+
460
+
350
461
/**
351
462
* Add a where between statement to the query.
352
463
*
@@ -716,12 +827,11 @@ public function convertKey($id)
716
827
public function where ($ column , $ operator = null , $ value = null , $ boolean = 'and ' )
717
828
{
718
829
$ params = func_get_args ();
719
-
830
+
720
831
// Remove the leading $ from operators.
721
832
if (func_num_args () == 3 )
722
833
{
723
834
$ operator = &$ params [1 ];
724
-
725
835
if (starts_with ($ operator , '$ ' ))
726
836
{
727
837
$ operator = substr ($ operator , 1 );
0 commit comments