Skip to content

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 fields

skip(n)

Skip a number of documents:

typescript
cursor.skip(20)  // Skip first 20 documents

limit(n)

Limit the number of results:

typescript
cursor.limit(10)  // Return at most 10 documents

project(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 _id

Execution Methods

toArray()

Execute and return results as an array:

typescript
const users = await cursor.toArray();
// Returns MonchArray<Doc> with .serialize() method

The 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 documents

serialize()

Execute and serialize in one step:

typescript
const users = await cursor.serialize();
// Returns Serialized<Doc>[] - plain objects

Equivalent 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:

OptionTypeDefaultDescription
pagenumber1Page number (1-based)
limitnumber20Items 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
}

Released under the MIT License.