@@ -57,6 +57,7 @@ class Watch implements Executable, /* @internal */ CommandSubscriber
57
57
private $ changeStreamOptions ;
58
58
private $ collectionName ;
59
59
private $ databaseName ;
60
+ private $ isFirstBatchIsEmpty = false ;
60
61
private $ operationTime ;
61
62
private $ pipeline ;
62
63
private $ resumeCallable ;
@@ -200,6 +201,12 @@ final public function commandFailed(CommandFailedEvent $event)
200
201
/** @internal */
201
202
final public function commandStarted (CommandStartedEvent $ event )
202
203
{
204
+ if ($ event ->getCommandName () !== 'aggregate ' ) {
205
+ return ;
206
+ }
207
+
208
+ $ this ->operationTime = null ;
209
+ $ this ->isFirstBatchIsEmpty = false ;
203
210
}
204
211
205
212
/** @internal */
@@ -214,6 +221,10 @@ final public function commandSucceeded(CommandSucceededEvent $event)
214
221
if (isset ($ reply ->operationTime ) && $ reply ->operationTime instanceof TimestampInterface) {
215
222
$ this ->operationTime = $ reply ->operationTime ;
216
223
}
224
+
225
+ if (isset ($ reply ->cursor ->firstBatch ) && is_array ($ reply ->cursor ->firstBatch )) {
226
+ $ this ->isFirstBatchIsEmpty = empty ($ reply ->cursor ->firstBatch );
227
+ }
217
228
}
218
229
219
230
/**
@@ -227,7 +238,9 @@ final public function commandSucceeded(CommandSucceededEvent $event)
227
238
*/
228
239
public function execute (Server $ server )
229
240
{
230
- return new ChangeStream ($ this ->executeAggregate ($ server ), $ this ->resumeCallable );
241
+ $ cursor = $ this ->executeAggregate ($ server );
242
+
243
+ return new ChangeStream ($ cursor , $ this ->resumeCallable , $ this ->isFirstBatchIsEmpty );
231
244
}
232
245
233
246
/**
@@ -255,40 +268,36 @@ private function createResumeCallable(Manager $manager)
255
268
unset($ this ->changeStreamOptions ['startAtOperationTime ' ]);
256
269
}
257
270
271
+ // Select a new server using the original read preference
272
+ $ server = $ manager ->selectServer ($ this ->aggregateOptions ['readPreference ' ]);
273
+
258
274
/* If we captured an operation time from the first aggregate command
259
275
* and there is no "resumeAfter" option, set "startAtOperationTime"
260
276
* so that we can resume from the original aggregate's time. */
261
- if ($ this ->operationTime !== null && ! isset ($ this ->changeStreamOptions ['resumeAfter ' ])) {
277
+ if ($ this ->operationTime !== null && ! isset ($ this ->changeStreamOptions ['resumeAfter ' ]) &&
278
+ \MongoDB \server_supports_feature ($ server , self ::$ wireVersionForStartAtOperationTime )) {
262
279
$ this ->changeStreamOptions ['startAtOperationTime ' ] = $ this ->operationTime ;
263
280
}
264
281
282
+ // Recreate the aggregate command and execute to obtain a new cursor
265
283
$ this ->aggregate = $ this ->createAggregate ();
284
+ $ cursor = $ this ->executeAggregate ($ server );
266
285
267
- /* Select a new server using the read preference, execute this
268
- * operation on it, and return the new ChangeStream. */
269
- $ server = $ manager ->selectServer ($ this ->aggregateOptions ['readPreference ' ]);
270
-
271
- return $ this ->execute ($ server );
286
+ return [$ cursor , $ this ->isFirstBatchIsEmpty ];
272
287
};
273
288
}
274
289
275
290
/**
276
- * Execute the aggregate command and optionally capture its operation time.
291
+ * Execute the aggregate command.
292
+ *
293
+ * The command will be executed using APM so that we can capture its
294
+ * operation time and/or firstBatch size.
277
295
*
278
296
* @param Server $server
279
297
* @return Cursor
280
298
*/
281
299
private function executeAggregate (Server $ server )
282
300
{
283
- /* If we've already captured an operation time or the server does not
284
- * support resuming from an operation time (e.g. MongoDB 3.6), execute
285
- * the aggregation directly and return its cursor. */
286
- if ($ this ->operationTime !== null || ! \MongoDB \server_supports_feature ($ server , self ::$ wireVersionForStartAtOperationTime )) {
287
- return $ this ->aggregate ->execute ($ server );
288
- }
289
-
290
- /* Otherwise, execute the aggregation using command monitoring so that
291
- * we can capture its operation time with commandSucceeded(). */
292
301
\MongoDB \Driver \Monitoring \addSubscriber ($ this );
293
302
294
303
try {
0 commit comments