Cursor
Chainable query cursor for building and executing queries.
Import
typescript
import { Cursor } from '@codician-team/monch';Creating a Cursor
Cursors are created by calling find() on a collection:
typescript
const cursor = Users.find({ status: 'active' });Chainable Methods
All chainable methods return the cursor for method chaining:
sort(spec)
Sort results by one or more fields:
typescript
cursor.sort({ createdAt: -1 }) // Descending
cursor.sort({ name: 1 }) // Ascending
cursor.sort({ role: 1, createdAt: -1 }) // Multiple fieldsskip(n)
Skip a number of documents:
typescript
cursor.skip(20) // Skip first 20 documentslimit(n)
Limit the number of results:
typescript
cursor.limit(10) // Return at most 10 documentsproject(spec)
Select or exclude fields:
typescript
cursor.project({ name: 1, email: 1 }) // Include only these
cursor.project({ password: 0 }) // Exclude this field
cursor.project({ name: 1, _id: 0 }) // Include name, exclude _idExecution Methods
toArray()
Execute and return results as an array:
typescript
const users = await cursor.toArray();
// Returns MonchArray<Doc> with .serialize() methodThe returned MonchArray is a regular array with an additional .serialize() method:
typescript
const users = await Users.find().toArray();
users.length; // Works (it's an array)
users.map(...); // Works
users.serialize(); // Serialize all documentsserialize()
Execute and serialize in one step:
typescript
const users = await cursor.serialize();
// Returns Serialized<Doc>[] - plain objectsEquivalent to .toArray() followed by .serialize(), but more concise.
paginate(opts?)
Execute with pagination metadata:
typescript
const result = await cursor.paginate({ page: 2, limit: 20 });Options:
| Option | Type | Default | Description |
|---|---|---|---|
page | number | 1 | Page number (1-based) |
limit | number | 20 | Items per page (max: 100) |
Returns:
typescript
{
data: Doc[], // Documents for this page
pagination: {
page: number, // Current page
limit: number, // Items per page
total: number, // Total matching documents
totalPages: number, // Total pages
hasNext: boolean, // Has more pages
hasPrev: boolean, // Has previous pages
}
}Limit Cap
The limit is silently capped at 100 to prevent loading too much data.
Usage Examples
Basic Query
typescript
const users = await Users.find({ role: 'admin' })
.sort({ name: 1 })
.toArray();With Pagination
typescript
const { data, pagination } = await Users.find({ status: 'active' })
.sort({ createdAt: -1 })
.paginate({ page: 1, limit: 20 });
console.log(`Page ${pagination.page} of ${pagination.totalPages}`);
console.log(`Showing ${data.length} of ${pagination.total} users`);For Next.js
typescript
// Server Component
const users = await Users.find({ role: 'admin' })
.sort({ createdAt: -1 })
.limit(10)
.serialize();
return <UserList users={users} />;Complex Query
typescript
const posts = await Posts.find({
status: 'published',
category: { $in: ['tech', 'science'] },
})
.sort({ publishedAt: -1, views: -1 })
.skip(20)
.limit(10)
.project({ title: 1, slug: 1, excerpt: 1, publishedAt: 1 })
.toArray();Type Safety
The cursor maintains type safety throughout:
typescript
const Users = collection({
name: 'users',
schema: {
_id: field.id(),
name: field.string(),
email: field.email(),
},
});
const users = await Users.find().toArray();
// users: MonchArray<{ _id: ObjectId; name: string; email: string }>
const serialized = await Users.find().serialize();
// serialized: { _id: string; name: string; email: string }[]PaginationResult Type
typescript
interface PaginationResult<T> {
data: T[];
pagination: {
page: number;
limit: number;
total: number;
totalPages: number;
hasNext: boolean;
hasPrev: boolean;
};
}PaginationOptions Type
typescript
interface PaginationOptions {
page?: number; // Default: 1
limit?: number; // Default: 20, max: 100
}