Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions docs/api/model.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,33 @@ userProjected.firstName; // TypeScript error
userProjected.lastName; // valid
```

## `findCursor`

Calls the MongoDB [`find()`](https://mongodb.github.io/node-mongodb-native/5.0/classes/Collection.html#find) method and returns the cursor.

Useful when you want to process many records without loading them all into
memory at once.

**Parameters:**

| Name | Type | Attribute |
| --------- | ---------------------- | --------- |
| `filter` | `PaprFilter<TSchema>` | required |
| `options` | `FindOptions<TSchema>` | optional |

**Example:**

```ts
const cursor = await User.findCursor(
{ active: true, email: { $exists: true } },
{ projection: { email: 1 } }
);

for await (const user of cursor) {
await notify(user.email);
}
```

## `findOne`

Calls the MongoDB [`findOne()`](https://mongodb.github.io/node-mongodb-native/5.0/classes/Collection.html#findOne) method.
Expand Down
33 changes: 32 additions & 1 deletion src/__tests__/model.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { beforeEach, describe, expect, jest, test } from '@jest/globals';
import { Collection, MongoError, ObjectId } from 'mongodb';
import { Collection, FindCursor, MongoError, ObjectId } from 'mongodb';
import { expectType } from 'ts-expect';
import { Hooks } from '../hooks';
import { abstract, build, Model } from '../model';
Expand Down Expand Up @@ -902,6 +902,37 @@ describe('model', () => {
});
});

describe('findCursor', () => {
test('default', async () => {
const cursor = await simpleModel.findCursor({});

expectType<FindCursor<SimpleDocument>>(cursor);
});

test('with projection', async () => {
const cursor = await simpleModel.findCursor(
{},
{
projection: {
...projection,
'nested.direct': 1,
},
}
);

expectType<
FindCursor<{
_id: ObjectId;
foo: string;
ham?: Date;
nested?: {
direct: string;
};
}>
>(cursor);
});
});

describe('findById', () => {
test('default', async () => {
const result = await simpleModel.findById('123456789012345678901234');
Expand Down
41 changes: 41 additions & 0 deletions src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {
DeleteResult,
DistinctOptions,
Filter,
FindCursor,
FindOneAndDeleteOptions,
FindOneAndUpdateOptions,
FindOptions,
Expand Down Expand Up @@ -86,6 +87,11 @@ export interface Model<TSchema extends BaseSchema, TOptions extends SchemaOption
options?: Omit<FindOptions<TSchema>, 'projection'> & { projection?: TProjection }
) => Promise<ProjectionType<TSchema, TProjection> | null>;

findCursor: <TProjection extends Projection<TSchema> | undefined>(
filter: PaprFilter<TSchema>,
options?: Omit<FindOptions<TSchema>, 'projection'> & { projection?: TProjection }
) => Promise<FindCursor<ProjectionType<TSchema, TProjection>>>;

findOne: <TProjection extends Projection<TSchema> | undefined>(
filter: PaprFilter<TSchema>,
options?: Omit<FindOptions<TSchema>, 'projection'> & { projection?: TProjection }
Expand Down Expand Up @@ -158,6 +164,7 @@ export function abstract<TSchema extends BaseSchema, TOptions extends SchemaOpti
deleteOne: abstractMethod,
find: abstractMethod,
findById: abstractMethod,
findCursor: abstractMethod,
findOne: abstractMethod,
findOneAndDelete: abstractMethod,
findOneAndUpdate: abstractMethod,
Expand Down Expand Up @@ -668,6 +675,40 @@ export function build<TSchema extends BaseSchema, TOptions extends SchemaOptions
}
);

/**
* @description
* Calls the MongoDB [`find()`](https://mongodb.github.io/node-mongodb-native/5.0/classes/Collection.html#find) method and returns the cursor.
*
* Useful when you want to process many records without loading them all into
* memory at once.
*
* @param filter {PaprFilter<TSchema>}
* @param [options] {FindOptions<TSchema>}
*
* @example
* const cursor = await User.findCursor(
* { active: true, email: { $exists: true } },
* { projection: { email: 1 } }
* )
*
* for await (const user of cursor) {
* await notify(user.email);
* }
*/
model.findCursor = wrap(model, async function findCursor<
TProjection extends Projection<TSchema> | undefined
>(filter: PaprFilter<TSchema>, options?: Omit<FindOptions<TSchema>, 'projection'> & { projection?: TProjection }): Promise<
FindCursor<ProjectionType<TSchema, TProjection>>
> {
return model.collection.find(
filter as Filter<TSchema>,
{
...model.defaultOptions,
...options,
} as FindOptions<TSchema>
) as FindCursor<ProjectionType<TSchema, TProjection>>;
});

/**
* @description
* Calls the MongoDB [`findOne()`](https://mongodb.github.io/node-mongodb-native/5.0/classes/Collection.html#findOne) method.
Expand Down