Skip to content

Commit

Permalink
cursor: Fix count function on aggregation cursor
Browse files Browse the repository at this point in the history
  • Loading branch information
BenjD90 committed Sep 20, 2023
1 parent 3edd345 commit 3a62a18
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 37 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Notable Changes

Upgrade main steps

- `yarn remove @neo9/n9-mongo-client && yarn add @neo9/n9-mongodb-client@^1.0.0-rc.2` (this also upgrade all transitive dependencies)
- `yarn remove @neo9/n9-mongo-client && yarn add @neo9/n9-mongodb-client@^1.0.0-rc.8` (this also upgrade all transitive dependencies)
- Rename usage : `find src/ -type f -exec sed -i -e 's#@neo9/n9-mongo-client#@neo9/n9-mongodb-client#g' {} +`
- Remove old mongodb types :

Expand All @@ -44,6 +44,8 @@ Upgrade main steps
- Upgrade MongoDb used for tests to version 6.0+
- Change MongoDB types imports from `import ... from 'mongodb';` to `import ... from '@neo9/n9-mongodb-client/mongodb';`
- Use Node.js version 16.20.2 or greater.
- Use new `count` function on `N9AggregationCursor` that wasn't available on `AggregationCursor`
- It's a good time to use new version of `@neo9/n9-mongodb-migration` V1 : `yarn upgrade @neo9/n9-mongodb-migration@^1.0.0-rc.0`

## To build

Expand Down
8 changes: 6 additions & 2 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1050,10 +1050,14 @@ export class MongoClient<U extends BaseMongoObject, L extends BaseMongoObject> {
): N9AggregationCursor<T> {
if (readInOutputCollection) {
const nativeCursor = this.collection.aggregate<T>(aggregateSteps, options);
return new N9AggregationCursor<T>(this.collection, nativeCursor);
return new N9AggregationCursor<T>(this.collection, nativeCursor, aggregateSteps);
}
const nativeCursor = this.collectionSourceForAggregation.aggregate<T>(aggregateSteps, options);
return new N9AggregationCursor<T>(this.collectionSourceForAggregation, nativeCursor);
return new N9AggregationCursor<T>(
this.collectionSourceForAggregation,
nativeCursor,
aggregateSteps,
);
}

public aggregateWithBuilder<T = void>(
Expand Down
47 changes: 22 additions & 25 deletions src/cursors/n9-aggregation-cursor.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,23 @@
import { N9Error } from '@neo9/n9-node-utils';
import * as _ from 'lodash';
import { AggregationCursor, Collection, Filter } from 'mongodb';
import { AggregationCursor, Collection } from 'mongodb';

import { LodashReplacerUtils } from '../lodash-replacer.utils';
import { N9AbstractCursor } from './n9-abstract-cursor';

export class N9AggregationCursor<E> extends N9AbstractCursor<E> {
private _filterQuery: Filter<E>; // can be edited with filter function

public constructor(
private readonly collection: Collection<any>,
private readonly aggregationCursor: AggregationCursor<E>,
private readonly aggregateSteps: object[],
) {
super(aggregationCursor);
}

/**
* Set the filterQuery used for count
*
* @param value
*/
set filterQuery(value: Filter<E>) {
this._filterQuery = value;
}

clone(): N9AggregationCursor<E> {
return new N9AggregationCursor<E>(this.collection, this.aggregationCursor.clone());
return new N9AggregationCursor<E>(
this.collection,
this.aggregationCursor.clone(),
this.aggregateSteps,
);
}

public async launch(): Promise<void> {
Expand All @@ -37,19 +30,23 @@ export class N9AggregationCursor<E> extends N9AbstractCursor<E> {
}

/**
* Get the count of documents for this cursor using the filterQuery.
*
* @see filterQuery
* Get the count of documents for this cursor.
*/
public async count(): Promise<number> {
if (!this._filterQuery) {
throw new N9Error('filter-query-not-initialized', 400, {
hint: 'Set filterQuery on the N9AggregationCursor before calling count function.',
});
}
if (_.isEmpty(this._filterQuery)) {
if (LodashReplacerUtils.IS_ARRAY_EMPTY(this.aggregateSteps)) {
return await this.collection.estimatedDocumentCount();
}
return await this.collection.countDocuments(this._filterQuery);
const countResult = await this.collection
.aggregate([
...this.aggregateSteps,
{
$group: {
_id: null,
n: { $sum: 1 },
},
},
])
.toArray();
return countResult[0].n;
}
}
4 changes: 2 additions & 2 deletions src/models/aggregate.models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -403,8 +403,8 @@ export interface GraphLookupPipelineStage {

/* GROUP */
export interface GroupPipelineStageValue {
_id: Expression;
[fieldName: string]: Expression;
_id: number | Expression;
[fieldName: string]: number | Expression;
}
export interface GroupPipelineStage {
[AggregationPipelineStageOperator.GROUP]: GroupPipelineStageValue;
Expand Down
3 changes: 3 additions & 0 deletions src/mongo-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ export class MongoUtils {

const optionsWithDefaultValuesApplied: mongodb.MongoClientOptions = {
heartbeatFrequencyMS: 3_000,
driverInfo: {
name: '@neo9/n9-mongodb-client',
},
...options,
};

Expand Down
11 changes: 4 additions & 7 deletions test/aggregation-cursor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,21 +83,18 @@ test('[Cursor] call hasNext before using in a for async', async (t: ExecutionCon

test('[Cursor] Check count function', async (t: ExecutionContext<ContextContent>) => {
let cursor = t.context.mongoClient.aggregate<SampleType>([]);
cursor.filterQuery = {};
t.is(await cursor.count(), 5, 'cursor contains 5 items');

const filterQuery = { field1String: { $regex: /[24680]$/ } };
cursor = t.context.mongoClient.aggregateWithBuilder<SampleType>(
t.context.mongoClient.newAggregationBuilder().match(filterQuery),
);
t.is(await cursor.count(), 2, 'cursor contains only odd => 2 elements');

await t.throwsAsync(
async () => await cursor.count(),
{ message: 'filter-query-not-initialized' },
'Should throw filter query not initialized error',
cursor = t.context.mongoClient.aggregateWithBuilder<SampleType>(
t.context.mongoClient.newAggregationBuilder().match(filterQuery).group({ _id: 1 }),
);
cursor.filterQuery = filterQuery;
t.is(await cursor.count(), 2, 'cursor contains only odd => 2 elements');
t.is(await cursor.count(), 1, 'cursor only contains the group result');
});

test('[Cursor] Check cursor clone function', async (t: ExecutionContext<ContextContent>) => {
Expand Down

0 comments on commit 3a62a18

Please sign in to comment.