Skip to content

Commit 9eef48a

Browse files
authored
fix(shell-api): run $out/$merge aggregations immediately MONGOSH-972 (#1108)
As suggested by the Node.js driver team, use `.hasNext()` to force sending the aggregation command to the server early.
1 parent f4e672b commit 9eef48a

File tree

5 files changed

+27
-3
lines changed

5 files changed

+27
-3
lines changed

packages/shell-api/src/collection.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ import {
2929
maybeMarkAsExplainOutput,
3030
markAsExplainOutput,
3131
assertArgsDefinedType,
32-
isValidCollectionName
32+
isValidCollectionName,
33+
shouldRunAggregationImmediately
3334
} from './helpers';
3435
import {
3536
AnyBulkWriteOperation,
@@ -180,6 +181,8 @@ export default class Collection extends ShellApiWithMongoClass {
180181

181182
if (explain) {
182183
return await cursor.explain(explain);
184+
} else if (shouldRunAggregationImmediately(pipeline)) {
185+
await cursor.hasNext();
183186
}
184187

185188
this._mongo._instanceState.currentCursor = cursor;

packages/shell-api/src/database.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2479,7 +2479,7 @@ describe('Database', () => {
24792479
const exceptions = {
24802480
getCollectionNames: { m: 'listCollections' },
24812481
getCollectionInfos: { m: 'listCollections' },
2482-
aggregate: { m: 'aggregateDb' },
2482+
aggregate: { m: 'aggregateDb', a: [[]] },
24832483
dropDatabase: { m: 'dropDatabase', i: 1 },
24842484
createCollection: { m: 'createCollection', a: ['coll'] },
24852485
createView: { m: 'createCollection', a: ['coll', 'source', []] },

packages/shell-api/src/database.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ import {
2121
processDigestPassword,
2222
tsToSeconds,
2323
isValidCollectionName,
24-
getConfigDB
24+
getConfigDB,
25+
shouldRunAggregationImmediately
2526
} from './helpers';
2627

2728
import type {
@@ -336,6 +337,8 @@ export default class Database extends ShellApiWithMongoClass {
336337

337338
if (explain) {
338339
return await cursor.explain(explain);
340+
} else if (shouldRunAggregationImmediately(pipeline)) {
341+
await cursor.hasNext();
339342
}
340343

341344
this._mongo._instanceState.currentCursor = cursor;

packages/shell-api/src/helpers.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,3 +716,9 @@ export function isValidDatabaseName(name: string): boolean {
716716
export function isValidCollectionName(name: string): boolean {
717717
return !!name && !/[$\0]/.test(name);
718718
}
719+
720+
export function shouldRunAggregationImmediately(pipeline: Document[]): boolean {
721+
return pipeline.some(stage =>
722+
Object.keys(stage).some(
723+
stageName => stageName === '$merge' || stageName === '$out'));
724+
}

packages/shell-api/src/integration.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,18 @@ describe('Shell API (integration)', function() {
916916
expect(await cursor.toArray()).to.have.length(0);
917917
});
918918

919+
it('runs the aggregation immediately if it is $merge/$out', async() => {
920+
const x = 123456789;
921+
await collection.insertOne({ x });
922+
923+
await collection.aggregate(
924+
{ $match: {} },
925+
{ $out: 'copy' }
926+
); // ignore the result
927+
928+
expect((await database.getCollection('copy').findOne()).x).to.equal(x);
929+
});
930+
919931
[true, false, 'queryPlanner'].forEach(explain => {
920932
it(`runs an explain with explain: ${explain}`, async() => {
921933
await serviceProvider.insertOne(dbName, collectionName, { x: 1 });

0 commit comments

Comments
 (0)