@zodmon/core 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +708 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2101 -954
- package/dist/index.d.ts +2101 -954
- package/dist/index.js +695 -44
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ObjectId, DeleteResult, FindCursor, Collection, UpdateResult, MongoClientOptions } from 'mongodb';
|
|
1
|
+
import { ObjectId, Document, DeleteResult, FindCursor, Collection, UpdateResult, MongoClientOptions } from 'mongodb';
|
|
2
2
|
import { ZodPipe, ZodCustom, ZodTransform, z, ZodDefault } from 'zod';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -253,11 +253,12 @@ type InferInsert<TDef extends {
|
|
|
253
253
|
* The immutable definition object returned by collection().
|
|
254
254
|
* Holds everything needed to later create a live collection handle.
|
|
255
255
|
*
|
|
256
|
+
* @typeParam TName - The collection name string literal.
|
|
256
257
|
* @typeParam TShape - The Zod shape defining document fields.
|
|
257
258
|
* @typeParam TIndexes - The compound indexes array type, preserving literal name types.
|
|
258
259
|
*/
|
|
259
|
-
type CollectionDefinition<TShape extends z.core.$ZodShape = z.core.$ZodShape, TIndexes extends readonly CompoundIndexDefinition<Extract<keyof TShape, string>>[] = readonly CompoundIndexDefinition<Extract<keyof TShape, string>>[]> = {
|
|
260
|
-
readonly name:
|
|
260
|
+
type CollectionDefinition<TName extends string = string, TShape extends z.core.$ZodShape = z.core.$ZodShape, TIndexes extends readonly CompoundIndexDefinition<Extract<keyof TShape, string>>[] = readonly CompoundIndexDefinition<Extract<keyof TShape, string>>[]> = {
|
|
261
|
+
readonly name: TName;
|
|
261
262
|
readonly schema: z.ZodObject<ResolvedShape<TShape>>;
|
|
262
263
|
readonly shape: TShape;
|
|
263
264
|
readonly fieldIndexes: FieldIndexDefinition[];
|
|
@@ -265,7 +266,7 @@ type CollectionDefinition<TShape extends z.core.$ZodShape = z.core.$ZodShape, TI
|
|
|
265
266
|
readonly options: Required<Pick<CollectionOptions, 'validation'>> & Omit<CollectionOptions, 'indexes' | 'validation'>;
|
|
266
267
|
};
|
|
267
268
|
/** Erased collection type for use in generic contexts. */
|
|
268
|
-
type AnyCollection = CollectionDefinition<z.core.$ZodShape>;
|
|
269
|
+
type AnyCollection = CollectionDefinition<string, z.core.$ZodShape>;
|
|
269
270
|
/**
|
|
270
271
|
* Extract declared index names from a collection definition.
|
|
271
272
|
*
|
|
@@ -304,1209 +305,2433 @@ type ExtractNames<T extends readonly {
|
|
|
304
305
|
}[number];
|
|
305
306
|
|
|
306
307
|
/**
|
|
307
|
-
*
|
|
308
|
+
* Forces TypeScript to eagerly expand mapped/intersection types in tooltips.
|
|
309
|
+
*
|
|
310
|
+
* Instead of showing `Omit<{ _id: ObjectId; name: string; salary: number }, "salary">`,
|
|
311
|
+
* the IDE will display the resolved shape `{ _id: ObjectId; name: string }`.
|
|
308
312
|
*
|
|
309
313
|
* @example
|
|
310
314
|
* ```ts
|
|
311
|
-
*
|
|
312
|
-
*
|
|
315
|
+
* type Expanded = Prettify<Pick<User, 'name' | 'role'>>
|
|
316
|
+
* // ^? { name: string; role: string }
|
|
313
317
|
* ```
|
|
314
318
|
*/
|
|
315
|
-
type
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
dropOrphaned?: boolean;
|
|
319
|
+
type Prettify<T> = {
|
|
320
|
+
[K in keyof T]: T[K];
|
|
321
|
+
} & {};
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Type-level marker that carries the target collection type through the
|
|
325
|
+
* type system. Intersected with the schema return type by `.ref()` so
|
|
326
|
+
* that `RefFields<T>` (future) can extract ref relationships.
|
|
327
|
+
*
|
|
328
|
+
* This is a phantom brand — no runtime value has this property.
|
|
329
|
+
*/
|
|
330
|
+
type RefMarker<TCollection extends AnyCollection = AnyCollection> = {
|
|
331
|
+
readonly _ref: TCollection;
|
|
329
332
|
};
|
|
330
333
|
/**
|
|
331
|
-
*
|
|
334
|
+
* Metadata stored in the WeakMap sidecar for schemas marked with `.ref()`.
|
|
335
|
+
* Holds a reference to the target collection definition object.
|
|
336
|
+
*/
|
|
337
|
+
type RefMetadata = {
|
|
338
|
+
readonly collection: AnyCollection;
|
|
339
|
+
};
|
|
340
|
+
/**
|
|
341
|
+
* Module augmentation: adds `.ref()` to all `ZodType` schemas.
|
|
332
342
|
*
|
|
333
|
-
*
|
|
334
|
-
*
|
|
343
|
+
* The intersection constraint `this['_zod']['output'] extends InferDocument<TCollection>['_id']`
|
|
344
|
+
* ensures compile-time type safety: the field's output type must match the
|
|
345
|
+
* target collection's `_id` type. Mismatches produce a type error.
|
|
346
|
+
*
|
|
347
|
+
* Supports both default ObjectId `_id` and custom `_id` types (string, nanoid, etc.):
|
|
348
|
+
* - `objectId().ref(Users)` compiles when Users has ObjectId `_id`
|
|
349
|
+
* - `z.string().ref(Orgs)` compiles when Orgs has string `_id`
|
|
350
|
+
* - `z.string().ref(Users)` is a type error (string ≠ ObjectId)
|
|
351
|
+
* - `objectId().ref(Orgs)` is a type error (ObjectId ≠ string)
|
|
352
|
+
*/
|
|
353
|
+
declare module 'zod' {
|
|
354
|
+
interface ZodType {
|
|
355
|
+
/**
|
|
356
|
+
* Declare a typed foreign key reference to another collection.
|
|
357
|
+
*
|
|
358
|
+
* Stores the target collection definition in metadata for runtime
|
|
359
|
+
* populate resolution, and brands the return type with
|
|
360
|
+
* `RefMarker<TCollection>` so `RefFields<T>` can extract refs
|
|
361
|
+
* at the type level.
|
|
362
|
+
*
|
|
363
|
+
* The field's output type must match the target collection's `_id` type.
|
|
364
|
+
* Mismatched types produce a compile error.
|
|
365
|
+
*
|
|
366
|
+
* Apply `.ref()` before wrapper methods like `.optional()` or `.nullable()`:
|
|
367
|
+
* `objectId().ref(Users).optional()` — not `objectId().optional().ref(Users)`.
|
|
368
|
+
*
|
|
369
|
+
* @param collection - The target collection definition object.
|
|
370
|
+
* @returns The same schema instance, branded with the ref marker.
|
|
371
|
+
*
|
|
372
|
+
* @example
|
|
373
|
+
* ```ts
|
|
374
|
+
* const Posts = collection('posts', {
|
|
375
|
+
* authorId: objectId().ref(Users),
|
|
376
|
+
* title: z.string(),
|
|
377
|
+
* })
|
|
378
|
+
* ```
|
|
379
|
+
*/
|
|
380
|
+
ref<TCollection extends AnyCollection>(collection: TCollection & (this['_zod']['output'] extends InferDocument<TCollection>['_id'] ? unknown : never)): this & RefMarker<TCollection>;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Retrieve the ref metadata attached to a Zod schema, if any.
|
|
385
|
+
*
|
|
386
|
+
* Returns `undefined` when the schema was never marked with `.ref()`.
|
|
387
|
+
*
|
|
388
|
+
* @param schema - The Zod schema to inspect. Accepts `unknown` for
|
|
389
|
+
* convenience; non-object values safely return `undefined`.
|
|
390
|
+
* @returns The {@link RefMetadata} for the schema, or `undefined`.
|
|
335
391
|
*
|
|
336
392
|
* @example
|
|
337
393
|
* ```ts
|
|
338
|
-
* const
|
|
339
|
-
*
|
|
340
|
-
*
|
|
341
|
-
* console.log(` existing=${JSON.stringify(s.existing)}`)
|
|
342
|
-
* console.log(` desired=${JSON.stringify(s.desired)}`)
|
|
343
|
-
* }
|
|
394
|
+
* const authorId = objectId().ref(Users)
|
|
395
|
+
* const meta = getRefMetadata(authorId)
|
|
396
|
+
* // => { collection: Users }
|
|
344
397
|
* ```
|
|
345
398
|
*/
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
name: string;
|
|
349
|
-
/** The index key spec (e.g. `{ email: 1 }`). */
|
|
350
|
-
key: Record<string, 1 | -1 | 'text'>;
|
|
351
|
-
/** The relevant options currently set on the existing index. */
|
|
352
|
-
existing: Record<string, unknown>;
|
|
353
|
-
/** The options the schema declares for this index. */
|
|
354
|
-
desired: Record<string, unknown>;
|
|
355
|
-
};
|
|
399
|
+
declare function getRefMetadata(schema: unknown): RefMetadata | undefined;
|
|
400
|
+
|
|
356
401
|
/**
|
|
357
|
-
*
|
|
402
|
+
* Branded wrapper for accumulator expressions used inside `groupBy`.
|
|
358
403
|
*
|
|
359
|
-
*
|
|
360
|
-
*
|
|
404
|
+
* Carries the MongoDB accumulator expression at runtime and the inferred
|
|
405
|
+
* result type `T` at the type level.
|
|
361
406
|
*
|
|
362
407
|
* @example
|
|
363
408
|
* ```ts
|
|
364
|
-
* const
|
|
365
|
-
*
|
|
366
|
-
*
|
|
367
|
-
*
|
|
368
|
-
* console.log('stale:', result.stale.map(s => s.name))
|
|
409
|
+
* const acc: Accumulator<number> = {
|
|
410
|
+
* __accum: true,
|
|
411
|
+
* expr: { $sum: '$price' },
|
|
412
|
+
* }
|
|
369
413
|
* ```
|
|
370
414
|
*/
|
|
371
|
-
type
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
/**
|
|
375
|
-
|
|
376
|
-
/** Names of indexes that already existed with matching options — no action taken. */
|
|
377
|
-
skipped: string[];
|
|
378
|
-
/** Indexes whose key matches a desired spec but whose options differ. */
|
|
379
|
-
stale: StaleIndex[];
|
|
415
|
+
type Accumulator<T = unknown> = {
|
|
416
|
+
readonly __accum: true;
|
|
417
|
+
readonly expr: Document;
|
|
418
|
+
/** @internal Phantom field — carries the result type at the type level. */
|
|
419
|
+
readonly _type?: T;
|
|
380
420
|
};
|
|
381
|
-
|
|
382
421
|
/**
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
* Maps each MongoDB comparison operator to its expected value type.
|
|
386
|
-
* `$regex` is only available when `V` extends `string`.
|
|
387
|
-
*
|
|
388
|
-
* Used as the operator object that can be assigned to a field in {@link TypedFilter}.
|
|
422
|
+
* Extracts the result type from an `Accumulator<T>`.
|
|
389
423
|
*
|
|
390
424
|
* @example
|
|
391
425
|
* ```ts
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
* // $regex only available on string fields
|
|
396
|
-
* const filter: TypedFilter<User> = { name: { $regex: /^A/i } }
|
|
426
|
+
* type Count = InferAccumulator<Accumulator<number>>
|
|
427
|
+
* // ^? number
|
|
397
428
|
* ```
|
|
398
429
|
*/
|
|
399
|
-
type
|
|
400
|
-
/** Matches values equal to the specified value. */
|
|
401
|
-
$eq?: V;
|
|
402
|
-
/** Matches values not equal to the specified value. */
|
|
403
|
-
$ne?: V;
|
|
404
|
-
/** Matches values greater than the specified value. */
|
|
405
|
-
$gt?: V;
|
|
406
|
-
/** Matches values greater than or equal to the specified value. */
|
|
407
|
-
$gte?: V;
|
|
408
|
-
/** Matches values less than the specified value. */
|
|
409
|
-
$lt?: V;
|
|
410
|
-
/** Matches values less than or equal to the specified value. */
|
|
411
|
-
$lte?: V;
|
|
412
|
-
/** Matches any value in the specified array. */
|
|
413
|
-
$in?: V[];
|
|
414
|
-
/** Matches none of the values in the specified array. */
|
|
415
|
-
$nin?: V[];
|
|
416
|
-
/** Matches documents where the field exists (`true`) or does not exist (`false`). */
|
|
417
|
-
$exists?: boolean;
|
|
418
|
-
/** Negates a comparison operator. */
|
|
419
|
-
$not?: ComparisonOperators<V>;
|
|
420
|
-
} & (V extends string ? {
|
|
421
|
-
$regex?: RegExp | string;
|
|
422
|
-
} : unknown);
|
|
423
|
-
/** Depth counter for limiting dot-notation recursion. Index = current depth, value = next depth. */
|
|
424
|
-
type Prev = [never, 0, 1, 2];
|
|
430
|
+
type InferAccumulator<T> = T extends Accumulator<infer R> ? R : never;
|
|
425
431
|
/**
|
|
426
|
-
*
|
|
432
|
+
* Maps an accumulator spec object to its inferred output shape.
|
|
427
433
|
*
|
|
428
|
-
*
|
|
429
|
-
*
|
|
430
|
-
* treated as leaf nodes and do not produce sub-paths.
|
|
434
|
+
* Given `{ count: Accumulator<number>, names: Accumulator<string[]> }`,
|
|
435
|
+
* produces `{ count: number, names: string[] }`.
|
|
431
436
|
*
|
|
432
437
|
* @example
|
|
433
438
|
* ```ts
|
|
434
|
-
* type
|
|
435
|
-
*
|
|
436
|
-
*
|
|
439
|
+
* type Spec = {
|
|
440
|
+
* count: Accumulator<number>
|
|
441
|
+
* total: Accumulator<number>
|
|
442
|
+
* }
|
|
443
|
+
* type Result = InferAccumulators<Spec>
|
|
444
|
+
* // ^? { count: number; total: number }
|
|
437
445
|
* ```
|
|
438
446
|
*/
|
|
439
|
-
type
|
|
440
|
-
[K in keyof T
|
|
441
|
-
}
|
|
447
|
+
type InferAccumulators<T extends Record<string, Accumulator>> = {
|
|
448
|
+
[K in keyof T]: InferAccumulator<T[K]>;
|
|
449
|
+
};
|
|
442
450
|
/**
|
|
443
|
-
*
|
|
444
|
-
*
|
|
445
|
-
* Splits `P` on the first `.` and recursively descends into `T`'s nested types.
|
|
446
|
-
* Returns `never` if the path is invalid.
|
|
451
|
+
* Field reference string prefixed with `$`, constrained to keys of `T`.
|
|
447
452
|
*
|
|
448
453
|
* @example
|
|
449
454
|
* ```ts
|
|
450
|
-
* type
|
|
451
|
-
*
|
|
452
|
-
* // DotPathType<User, 'address.city'> = string
|
|
453
|
-
* // DotPathType<User, 'address.geo.lat'> = number
|
|
455
|
+
* type OrderRef = FieldRef<{ price: number; qty: number }>
|
|
456
|
+
* // ^? '$price' | '$qty'
|
|
454
457
|
* ```
|
|
455
458
|
*/
|
|
456
|
-
type
|
|
459
|
+
type FieldRef<T> = `$${keyof T & string}`;
|
|
457
460
|
/**
|
|
458
|
-
*
|
|
459
|
-
*
|
|
460
|
-
* Validates filter objects at compile time — rejects nonexistent fields, type mismatches,
|
|
461
|
-
* and invalid operator usage. Unlike the MongoDB driver's `Filter<T>`, does NOT allow
|
|
462
|
-
* arbitrary keys via `& Document`.
|
|
461
|
+
* Typed accumulator factory passed to the `groupBy` callback.
|
|
463
462
|
*
|
|
464
|
-
*
|
|
465
|
-
*
|
|
466
|
-
*
|
|
467
|
-
* - **Dot notation** for nested fields up to 3 levels: `{ 'address.city': 'NYC' }`
|
|
463
|
+
* Each method constrains field names to `keyof T & string`, providing
|
|
464
|
+
* IDE autocomplete and compile-time validation. Return types resolve
|
|
465
|
+
* to the actual field type (`T[K]`), not `unknown`.
|
|
468
466
|
*
|
|
469
|
-
*
|
|
470
|
-
* for composing complex queries.
|
|
467
|
+
* @typeParam T - The current pipeline output document type.
|
|
471
468
|
*
|
|
472
469
|
* @example
|
|
473
470
|
* ```ts
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
*
|
|
477
|
-
* //
|
|
478
|
-
*
|
|
479
|
-
*
|
|
480
|
-
*
|
|
481
|
-
* posts.find($and(
|
|
482
|
-
* $or({ published: true }, { views: $gte(100) }),
|
|
483
|
-
* { title: $regex(/guide/i) },
|
|
484
|
-
* ))
|
|
485
|
-
*
|
|
486
|
-
* // Dynamic conditional building
|
|
487
|
-
* const conditions: TypedFilter<User>[] = []
|
|
488
|
-
* if (name) conditions.push({ name })
|
|
489
|
-
* if (minAge) conditions.push({ age: $gte(minAge) })
|
|
490
|
-
* const filter = conditions.length ? $and<User>(...conditions) : {}
|
|
471
|
+
* users.aggregate()
|
|
472
|
+
* .groupBy('role', acc => ({
|
|
473
|
+
* minSalary: acc.min('salary'), // Accumulator<number>
|
|
474
|
+
* firstName: acc.first('name'), // Accumulator<string>
|
|
475
|
+
* allNames: acc.push('name'), // Accumulator<string[]>
|
|
476
|
+
* count: acc.count(), // Accumulator<number>
|
|
477
|
+
* }))
|
|
491
478
|
* ```
|
|
492
479
|
*/
|
|
493
|
-
type
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
/**
|
|
499
|
-
|
|
500
|
-
/**
|
|
501
|
-
|
|
502
|
-
/**
|
|
503
|
-
|
|
480
|
+
type AccumulatorBuilder<T> = {
|
|
481
|
+
/** Count documents in each group. Always returns `Accumulator<number>`. */
|
|
482
|
+
count(): Accumulator<number>;
|
|
483
|
+
/** Sum a numeric field. Always returns `Accumulator<number>`. */
|
|
484
|
+
sum<K extends keyof T & string>(field: K): Accumulator<number>;
|
|
485
|
+
/** Sum a literal number per document. Always returns `Accumulator<number>`. */
|
|
486
|
+
sum(value: number): Accumulator<number>;
|
|
487
|
+
/** Average a numeric field. Always returns `Accumulator<number>`. */
|
|
488
|
+
avg<K extends keyof T & string>(field: K): Accumulator<number>;
|
|
489
|
+
/** Minimum value of a field. Returns `Accumulator<T[K]>`. */
|
|
490
|
+
min<K extends keyof T & string>(field: K): Accumulator<T[K]>;
|
|
491
|
+
/** Maximum value of a field. Returns `Accumulator<T[K]>`. */
|
|
492
|
+
max<K extends keyof T & string>(field: K): Accumulator<T[K]>;
|
|
493
|
+
/** First value in each group (by document order). Returns `Accumulator<T[K]>`. */
|
|
494
|
+
first<K extends keyof T & string>(field: K): Accumulator<T[K]>;
|
|
495
|
+
/** Last value in each group (by document order). Returns `Accumulator<T[K]>`. */
|
|
496
|
+
last<K extends keyof T & string>(field: K): Accumulator<T[K]>;
|
|
497
|
+
/** Collect values into an array (with duplicates). Returns `Accumulator<T[K][]>`. */
|
|
498
|
+
push<K extends keyof T & string>(field: K): Accumulator<T[K][]>;
|
|
499
|
+
/** Collect unique values into an array. Returns `Accumulator<T[K][]>`. */
|
|
500
|
+
addToSet<K extends keyof T & string>(field: K): Accumulator<T[K][]>;
|
|
504
501
|
};
|
|
505
|
-
|
|
506
502
|
/**
|
|
507
|
-
*
|
|
503
|
+
* Resolves the document field type from a `$`-prefixed field reference.
|
|
504
|
+
*
|
|
505
|
+
* @example
|
|
506
|
+
* ```ts
|
|
507
|
+
* type Order = { price: number; name: string }
|
|
508
|
+
* type PriceType = FieldRefType<Order, '$price'>
|
|
509
|
+
* // ^? number
|
|
510
|
+
* ```
|
|
508
511
|
*/
|
|
509
|
-
type
|
|
510
|
-
/** Override the collection-level validation mode, or `false` to skip validation entirely. */
|
|
511
|
-
validate?: ValidationMode | false;
|
|
512
|
-
};
|
|
512
|
+
type FieldRefType<T, F extends string> = F extends `$${infer K}` ? K extends keyof T ? T[K] : never : never;
|
|
513
513
|
/**
|
|
514
|
-
*
|
|
514
|
+
* Output shape of a single-field `groupBy` stage.
|
|
515
515
|
*
|
|
516
|
-
*
|
|
517
|
-
*
|
|
518
|
-
* the MongoDB driver.
|
|
519
|
-
*
|
|
520
|
-
* @param handle - The collection handle to delete from.
|
|
521
|
-
* @param filter - Type-safe filter to match documents.
|
|
522
|
-
* @returns The MongoDB `DeleteResult` with the deleted count.
|
|
516
|
+
* The `_id` field holds the grouped-by field's value, and the rest of the
|
|
517
|
+
* shape comes from the inferred accumulator types.
|
|
523
518
|
*
|
|
524
519
|
* @example
|
|
525
520
|
* ```ts
|
|
526
|
-
*
|
|
527
|
-
*
|
|
521
|
+
* type Result = GroupByResult<Order, 'status', { count: Accumulator<number> }>
|
|
522
|
+
* // ^? { _id: string; count: number }
|
|
528
523
|
* ```
|
|
529
524
|
*/
|
|
530
|
-
|
|
525
|
+
type GroupByResult<T, K extends keyof T, TAccum extends Record<string, Accumulator>> = Prettify<{
|
|
526
|
+
_id: T[K];
|
|
527
|
+
} & InferAccumulators<TAccum>>;
|
|
531
528
|
/**
|
|
532
|
-
*
|
|
533
|
-
*
|
|
534
|
-
* Removes every document that matches the filter from the collection.
|
|
535
|
-
* No validation is performed — documents are deleted directly through
|
|
536
|
-
* the MongoDB driver.
|
|
529
|
+
* Output shape of a compound (multi-field) `groupBy` stage.
|
|
537
530
|
*
|
|
538
|
-
*
|
|
539
|
-
*
|
|
540
|
-
* @returns The MongoDB `DeleteResult` with the deleted count.
|
|
531
|
+
* The `_id` field is an object with one property per grouped field,
|
|
532
|
+
* and the rest of the shape comes from the inferred accumulator types.
|
|
541
533
|
*
|
|
542
534
|
* @example
|
|
543
535
|
* ```ts
|
|
544
|
-
*
|
|
545
|
-
*
|
|
536
|
+
* type Result = GroupByCompoundResult<Order, 'status' | 'region', { count: Accumulator<number> }>
|
|
537
|
+
* // ^? { _id: Pick<Order, 'status' | 'region'>; count: number }
|
|
546
538
|
* ```
|
|
547
539
|
*/
|
|
548
|
-
|
|
540
|
+
type GroupByCompoundResult<T, K extends keyof T, TAccum extends Record<string, Accumulator>> = Prettify<{
|
|
541
|
+
_id: Prettify<Pick<T, K>>;
|
|
542
|
+
} & InferAccumulators<TAccum>>;
|
|
549
543
|
/**
|
|
550
|
-
*
|
|
544
|
+
* Output shape after unwinding an array field.
|
|
551
545
|
*
|
|
552
|
-
*
|
|
553
|
-
*
|
|
554
|
-
* using the same resolution logic as {@link findOne}.
|
|
546
|
+
* The unwound field's type changes from `Array<E>` to `E`; all other
|
|
547
|
+
* fields are preserved as-is.
|
|
555
548
|
*
|
|
556
|
-
* @
|
|
557
|
-
*
|
|
558
|
-
*
|
|
559
|
-
*
|
|
560
|
-
*
|
|
549
|
+
* @example
|
|
550
|
+
* ```ts
|
|
551
|
+
* type Order = { items: string[]; total: number }
|
|
552
|
+
* type Unwound = UnwindResult<Order, 'items'>
|
|
553
|
+
* // ^? { items: string; total: number }
|
|
554
|
+
* ```
|
|
555
|
+
*/
|
|
556
|
+
type UnwindResult<T, K extends keyof T> = {
|
|
557
|
+
[P in keyof T]: P extends K ? (T[P] extends ReadonlyArray<infer E> ? E : T[P]) : T[P];
|
|
558
|
+
};
|
|
559
|
+
/**
|
|
560
|
+
* Narrows document field types based on a filter expression.
|
|
561
|
+
*
|
|
562
|
+
* Inspects each field in the filter for value-constraining operators
|
|
563
|
+
* (`$eq`, `$in`, `$ne`, `$nin`, or direct equality) and narrows the
|
|
564
|
+
* corresponding field type in the output. Fields not mentioned in the
|
|
565
|
+
* filter, or filtered with unsupported operators, keep their original type.
|
|
566
|
+
*
|
|
567
|
+
* Used internally by {@link AggregatePipeline.match} for automatic
|
|
568
|
+
* type narrowing (Tier 2). Requires `as const` on array literals
|
|
569
|
+
* for `$in` / `$nin` inference.
|
|
561
570
|
*
|
|
562
571
|
* @example
|
|
563
572
|
* ```ts
|
|
564
|
-
*
|
|
565
|
-
*
|
|
573
|
+
* type Narrowed = NarrowFromFilter<Employee, { role: 'engineer' }>
|
|
574
|
+
* // ^? { ..., role: 'engineer', ... }
|
|
575
|
+
*
|
|
576
|
+
* type Subset = NarrowFromFilter<Employee, { role: { $in: readonly ['engineer', 'designer'] } }>
|
|
577
|
+
* // ^? { ..., role: 'engineer' | 'designer', ... }
|
|
578
|
+
*
|
|
579
|
+
* type Excluded = NarrowFromFilter<Employee, { role: { $ne: 'intern' } }>
|
|
580
|
+
* // ^? { ..., role: 'engineer' | 'manager' | 'designer', ... }
|
|
566
581
|
* ```
|
|
582
|
+
*/
|
|
583
|
+
type NarrowFromFilter<T, F> = {
|
|
584
|
+
[K in keyof T]: K extends keyof F ? F[K] extends T[K] ? F[K] : F[K] extends {
|
|
585
|
+
$eq: infer V extends T[K];
|
|
586
|
+
} ? V : F[K] extends {
|
|
587
|
+
$in: ReadonlyArray<infer V extends T[K]>;
|
|
588
|
+
} ? V : F[K] extends {
|
|
589
|
+
$ne: infer V extends T[K];
|
|
590
|
+
} ? Exclude<T[K], V> : F[K] extends {
|
|
591
|
+
$nin: ReadonlyArray<infer V extends T[K]>;
|
|
592
|
+
} ? Exclude<T[K], V> : T[K] : T[K];
|
|
593
|
+
};
|
|
594
|
+
/**
|
|
595
|
+
* Extract field keys from a collection definition whose schema fields
|
|
596
|
+
* carry `RefMarker` (i.e. fields that have `.ref()` metadata).
|
|
567
597
|
*
|
|
568
598
|
* @example
|
|
569
599
|
* ```ts
|
|
570
|
-
*
|
|
571
|
-
* users,
|
|
572
|
-
* { role: 'guest' },
|
|
573
|
-
* { validate: false },
|
|
574
|
-
* )
|
|
600
|
+
* type EmpRefs = RefFields<typeof Employees> // → 'departmentId'
|
|
575
601
|
* ```
|
|
576
602
|
*/
|
|
577
|
-
|
|
578
|
-
|
|
603
|
+
type RefFields<TDef extends AnyCollection> = {
|
|
604
|
+
[K in keyof TDef['shape'] & string]: TDef['shape'][K] extends RefMarker ? K : never;
|
|
605
|
+
}[keyof TDef['shape'] & string];
|
|
579
606
|
/**
|
|
580
|
-
*
|
|
607
|
+
* Given a collection definition and a ref-bearing field key, extract
|
|
608
|
+
* the target collection type from the `RefMarker<TCollection>` phantom.
|
|
581
609
|
*
|
|
582
610
|
* @example
|
|
583
611
|
* ```ts
|
|
584
|
-
*
|
|
612
|
+
* type Target = ExtractRefCollection<typeof Employees, 'departmentId'>
|
|
613
|
+
* // → typeof Departments
|
|
585
614
|
* ```
|
|
586
615
|
*/
|
|
587
|
-
type
|
|
588
|
-
/** The page number to retrieve (1-indexed). */
|
|
589
|
-
page: number;
|
|
590
|
-
/** The number of documents per page. */
|
|
591
|
-
perPage: number;
|
|
592
|
-
};
|
|
616
|
+
type ExtractRefCollection<TDef extends AnyCollection, K extends RefFields<TDef>> = TDef['shape'][K] extends RefMarker<infer TCol> ? TCol : never;
|
|
593
617
|
/**
|
|
594
|
-
*
|
|
618
|
+
* Extract the collection name string literal from a collection definition.
|
|
595
619
|
*
|
|
596
620
|
* @example
|
|
597
621
|
* ```ts
|
|
598
|
-
*
|
|
599
|
-
* const next = await users.find({}).sort({ name: 1 }).paginate({ cursor: first.endCursor, limit: 10 })
|
|
622
|
+
* CollectionName<typeof Departments> // → 'departments'
|
|
600
623
|
* ```
|
|
601
624
|
*/
|
|
602
|
-
type
|
|
603
|
-
/** Maximum number of documents to return. */
|
|
604
|
-
limit: number;
|
|
605
|
-
/** Opaque cursor string from a previous `startCursor` or `endCursor`. */
|
|
606
|
-
cursor?: string | null;
|
|
607
|
-
};
|
|
625
|
+
type CollectionName<TDef extends AnyCollection> = TDef['name'];
|
|
608
626
|
/**
|
|
609
|
-
*
|
|
627
|
+
* Branded wrapper for computed expressions used inside `addFields`.
|
|
628
|
+
*
|
|
629
|
+
* Carries the MongoDB expression at runtime and the inferred
|
|
630
|
+
* result type `T` at the type level.
|
|
610
631
|
*
|
|
611
632
|
* @example
|
|
612
633
|
* ```ts
|
|
613
|
-
* const
|
|
614
|
-
*
|
|
634
|
+
* const yearExpr: Expression<number> = {
|
|
635
|
+
* __expr: true,
|
|
636
|
+
* value: { $year: '$hiredAt' },
|
|
637
|
+
* }
|
|
615
638
|
* ```
|
|
616
639
|
*/
|
|
617
|
-
type
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
/**
|
|
621
|
-
|
|
622
|
-
/** Current page number (1-indexed). */
|
|
623
|
-
page: number;
|
|
624
|
-
/** Number of documents per page. */
|
|
625
|
-
perPage: number;
|
|
626
|
-
/** Total number of pages (`Math.ceil(total / perPage)`). */
|
|
627
|
-
totalPages: number;
|
|
628
|
-
/** Whether there is a next page. */
|
|
629
|
-
hasNext: boolean;
|
|
630
|
-
/** Whether there is a previous page. */
|
|
631
|
-
hasPrev: boolean;
|
|
640
|
+
type Expression<T = unknown> = {
|
|
641
|
+
readonly __expr: true;
|
|
642
|
+
readonly value: Document;
|
|
643
|
+
/** @internal Phantom field — carries the result type at the type level. */
|
|
644
|
+
readonly _type?: T;
|
|
632
645
|
};
|
|
633
646
|
/**
|
|
634
|
-
*
|
|
647
|
+
* Unwrap an `Expression<T>` to its result type `T`.
|
|
648
|
+
* Non-Expression values resolve to `unknown`.
|
|
635
649
|
*
|
|
636
650
|
* @example
|
|
637
651
|
* ```ts
|
|
638
|
-
*
|
|
639
|
-
*
|
|
640
|
-
* const next = await users.find({}).paginate({ cursor: page.endCursor, limit: 10 })
|
|
641
|
-
* }
|
|
652
|
+
* type N = InferExpression<Expression<number>> // → number
|
|
653
|
+
* type U = InferExpression<{ $year: string }> // → unknown
|
|
642
654
|
* ```
|
|
643
655
|
*/
|
|
644
|
-
type
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
656
|
+
type InferExpression<T> = T extends Expression<infer R> ? R : unknown;
|
|
657
|
+
/**
|
|
658
|
+
* Map an added-fields spec to its resolved output shape.
|
|
659
|
+
*
|
|
660
|
+
* `Expression<V>` values unwrap to `V`. Raw expression objects resolve
|
|
661
|
+
* to `unknown`, signaling that type information is lost.
|
|
662
|
+
*
|
|
663
|
+
* @example
|
|
664
|
+
* ```ts
|
|
665
|
+
* type Spec = { year: Expression<number>; raw: { $year: string } }
|
|
666
|
+
* type Result = InferAddedFields<Spec>
|
|
667
|
+
* // ^? { year: number; raw: unknown }
|
|
668
|
+
* ```
|
|
669
|
+
*/
|
|
670
|
+
type InferAddedFields<T extends Record<string, unknown>> = {
|
|
671
|
+
[K in keyof T]: InferExpression<T[K]>;
|
|
672
|
+
};
|
|
673
|
+
/**
|
|
674
|
+
* Typed expression factory passed to the `addFields` callback.
|
|
675
|
+
*
|
|
676
|
+
* Each method constrains field names to `keyof T & string`, providing
|
|
677
|
+
* IDE autocomplete and compile-time validation. Return types resolve
|
|
678
|
+
* to `Expression<R>` where `R` is the MongoDB operator's output type.
|
|
679
|
+
*
|
|
680
|
+
* @typeParam T - The current pipeline output document type.
|
|
681
|
+
*
|
|
682
|
+
* @example
|
|
683
|
+
* ```ts
|
|
684
|
+
* employees.aggregate()
|
|
685
|
+
* .addFields(expr => ({
|
|
686
|
+
* hireYear: expr.year('hiredAt'), // Expression<number>
|
|
687
|
+
* fullName: expr.concat('name', ' '), // Expression<string>
|
|
688
|
+
* isHighPay: expr.gte('salary', 100_000), // Expression<boolean>
|
|
689
|
+
* }))
|
|
690
|
+
* ```
|
|
691
|
+
*/
|
|
692
|
+
type ExpressionBuilder<T> = {
|
|
693
|
+
/** Add a numeric field and a value. Returns `Expression<number>`. */
|
|
694
|
+
add<K extends keyof T & string>(field: K, value: number | (keyof T & string)): Expression<number>;
|
|
695
|
+
/** Subtract a value from a numeric field. Returns `Expression<number>`. */
|
|
696
|
+
subtract<K extends keyof T & string>(field: K, value: number | (keyof T & string)): Expression<number>;
|
|
697
|
+
/** Multiply a numeric field by a value. Returns `Expression<number>`. */
|
|
698
|
+
multiply<K extends keyof T & string>(field: K, value: number | (keyof T & string)): Expression<number>;
|
|
699
|
+
/** Divide a numeric field by a value. Returns `Expression<number>`. */
|
|
700
|
+
divide<K extends keyof T & string>(field: K, value: number | (keyof T & string)): Expression<number>;
|
|
701
|
+
/** Modulo of a numeric field. Returns `Expression<number>`. */
|
|
702
|
+
mod<K extends keyof T & string>(field: K, value: number | (keyof T & string)): Expression<number>;
|
|
703
|
+
/** Absolute value of a numeric field. Returns `Expression<number>`. */
|
|
704
|
+
abs<K extends keyof T & string>(field: K): Expression<number>;
|
|
705
|
+
/** Ceiling of a numeric field. Returns `Expression<number>`. */
|
|
706
|
+
ceil<K extends keyof T & string>(field: K): Expression<number>;
|
|
707
|
+
/** Floor of a numeric field. Returns `Expression<number>`. */
|
|
708
|
+
floor<K extends keyof T & string>(field: K): Expression<number>;
|
|
709
|
+
/** Round a numeric field to N decimal places. Returns `Expression<number>`. */
|
|
710
|
+
round<K extends keyof T & string>(field: K, place?: number): Expression<number>;
|
|
711
|
+
/** Concatenate field values and literal strings. Returns `Expression<string>`. */
|
|
712
|
+
concat(...parts: Array<(keyof T & string) | string>): Expression<string>;
|
|
713
|
+
/** Convert a string field to lowercase. Returns `Expression<string>`. */
|
|
714
|
+
toLower<K extends keyof T & string>(field: K): Expression<string>;
|
|
715
|
+
/** Convert a string field to uppercase. Returns `Expression<string>`. */
|
|
716
|
+
toUpper<K extends keyof T & string>(field: K): Expression<string>;
|
|
717
|
+
/** Trim whitespace from a string field. Returns `Expression<string>`. */
|
|
718
|
+
trim<K extends keyof T & string>(field: K): Expression<string>;
|
|
719
|
+
/** Extract a substring from a string field. Returns `Expression<string>`. */
|
|
720
|
+
substr<K extends keyof T & string>(field: K, start: number, length: number): Expression<string>;
|
|
721
|
+
/** Test equality of a field against a value. Returns `Expression<boolean>`. */
|
|
722
|
+
eq<K extends keyof T & string>(field: K, value: T[K]): Expression<boolean>;
|
|
723
|
+
/** Test if a field is greater than a value. Returns `Expression<boolean>`. */
|
|
724
|
+
gt<K extends keyof T & string>(field: K, value: T[K]): Expression<boolean>;
|
|
725
|
+
/** Test if a field is greater than or equal to a value. Returns `Expression<boolean>`. */
|
|
726
|
+
gte<K extends keyof T & string>(field: K, value: T[K]): Expression<boolean>;
|
|
727
|
+
/** Test if a field is less than a value. Returns `Expression<boolean>`. */
|
|
728
|
+
lt<K extends keyof T & string>(field: K, value: T[K]): Expression<boolean>;
|
|
729
|
+
/** Test if a field is less than or equal to a value. Returns `Expression<boolean>`. */
|
|
730
|
+
lte<K extends keyof T & string>(field: K, value: T[K]): Expression<boolean>;
|
|
731
|
+
/** Test if a field is not equal to a value. Returns `Expression<boolean>`. */
|
|
732
|
+
ne<K extends keyof T & string>(field: K, value: T[K]): Expression<boolean>;
|
|
733
|
+
/** Extract year from a date field. Returns `Expression<number>`. */
|
|
734
|
+
year<K extends keyof T & string>(field: K): Expression<number>;
|
|
735
|
+
/** Extract month (1-12) from a date field. Returns `Expression<number>`. */
|
|
736
|
+
month<K extends keyof T & string>(field: K): Expression<number>;
|
|
737
|
+
/** Extract day of month (1-31) from a date field. Returns `Expression<number>`. */
|
|
738
|
+
dayOfMonth<K extends keyof T & string>(field: K): Expression<number>;
|
|
739
|
+
/** Count elements in an array field. Returns `Expression<number>`. */
|
|
740
|
+
size<K extends keyof T & string>(field: K): Expression<number>;
|
|
741
|
+
/** Conditional expression. Returns `Expression<TThen | TElse>`. */
|
|
742
|
+
cond<TThen, TElse>(condition: Expression<boolean>, thenValue: TThen, elseValue: TElse): Expression<TThen | TElse>;
|
|
743
|
+
/** Replace null/missing field with a default. Returns `Expression<NonNullable<T[K]> | TDefault>`. */
|
|
744
|
+
ifNull<K extends keyof T & string, TDefault>(field: K, fallback: TDefault): Expression<NonNullable<T[K]> | TDefault>;
|
|
655
745
|
};
|
|
656
746
|
|
|
657
747
|
/**
|
|
658
|
-
*
|
|
748
|
+
* Counts the number of documents in each group.
|
|
659
749
|
*
|
|
660
|
-
*
|
|
661
|
-
*
|
|
750
|
+
* Equivalent to `{ $sum: 1 }` in a MongoDB `$group` stage.
|
|
751
|
+
*
|
|
752
|
+
* @returns An `Accumulator<number>` that counts documents.
|
|
662
753
|
*
|
|
663
754
|
* @example
|
|
664
755
|
* ```ts
|
|
665
|
-
* const
|
|
756
|
+
* const pipeline = orders.aggregate()
|
|
757
|
+
* .groupBy('status', { count: $count() })
|
|
666
758
|
* ```
|
|
667
759
|
*/
|
|
668
|
-
|
|
760
|
+
declare const $count: () => Accumulator<number>;
|
|
669
761
|
/**
|
|
670
|
-
*
|
|
762
|
+
* Sums numeric values across documents in each group.
|
|
671
763
|
*
|
|
672
|
-
*
|
|
673
|
-
* `this` for fluent chaining, and terminal methods (`toArray`,
|
|
674
|
-
* `[Symbol.asyncIterator]`) that validate each document against the
|
|
675
|
-
* collection's Zod schema before returning.
|
|
764
|
+
* Accepts either a `$`-prefixed field reference or a literal number.
|
|
676
765
|
*
|
|
677
|
-
*
|
|
766
|
+
* @param field - A `$field` reference to a numeric field, or a literal number.
|
|
767
|
+
* @returns An `Accumulator<number>`.
|
|
678
768
|
*
|
|
679
|
-
* @
|
|
680
|
-
*
|
|
769
|
+
* @example
|
|
770
|
+
* ```ts
|
|
771
|
+
* const pipeline = orders.aggregate()
|
|
772
|
+
* .groupBy('status', {
|
|
773
|
+
* total: $sum('$amount'),
|
|
774
|
+
* fixed: $sum(1),
|
|
775
|
+
* })
|
|
776
|
+
* ```
|
|
777
|
+
*/
|
|
778
|
+
declare const $sum: (field: `$${string}` | number) => Accumulator<number>;
|
|
779
|
+
/**
|
|
780
|
+
* Computes the average of numeric values across documents in each group.
|
|
781
|
+
*
|
|
782
|
+
* @param field - A `$field` reference to a numeric field.
|
|
783
|
+
* @returns An `Accumulator<number>`.
|
|
681
784
|
*
|
|
682
785
|
* @example
|
|
683
786
|
* ```ts
|
|
684
|
-
* const
|
|
685
|
-
*
|
|
686
|
-
* .limit(10)
|
|
687
|
-
* .toArray()
|
|
787
|
+
* const pipeline = orders.aggregate()
|
|
788
|
+
* .groupBy('category', { avgPrice: $avg('$price') })
|
|
688
789
|
* ```
|
|
689
790
|
*/
|
|
690
|
-
declare
|
|
691
|
-
/** @internal */
|
|
692
|
-
private cursor;
|
|
693
|
-
/** @internal */
|
|
694
|
-
private schema;
|
|
695
|
-
/** @internal */
|
|
696
|
-
private collectionName;
|
|
697
|
-
/** @internal */
|
|
698
|
-
private mode;
|
|
699
|
-
/** @internal */
|
|
700
|
-
private readonly nativeCollection;
|
|
701
|
-
/** @internal */
|
|
702
|
-
private readonly filter;
|
|
703
|
-
/** @internal */
|
|
704
|
-
private sortSpec;
|
|
705
|
-
/** @internal */
|
|
706
|
-
constructor(cursor: FindCursor<InferDocument<TDef>>, definition: TDef, mode: ValidationMode | false, nativeCollection: Collection<InferDocument<TDef>>, filter: any);
|
|
707
|
-
/**
|
|
708
|
-
* Set the sort order for the query.
|
|
709
|
-
*
|
|
710
|
-
* Only top-level document fields are accepted as sort keys.
|
|
711
|
-
* Values must be `1` (ascending) or `-1` (descending).
|
|
712
|
-
*
|
|
713
|
-
* @param spec - Sort specification mapping field names to sort direction.
|
|
714
|
-
* @returns `this` for chaining.
|
|
715
|
-
*
|
|
716
|
-
* @example
|
|
717
|
-
* ```ts
|
|
718
|
-
* find(users, {}).sort({ name: 1, age: -1 }).toArray()
|
|
719
|
-
* ```
|
|
720
|
-
*/
|
|
721
|
-
sort(spec: TypedSort<InferDocument<TDef>>): this;
|
|
722
|
-
/**
|
|
723
|
-
* Skip the first `n` documents in the result set.
|
|
724
|
-
*
|
|
725
|
-
* @param n - Number of documents to skip.
|
|
726
|
-
* @returns `this` for chaining.
|
|
727
|
-
*
|
|
728
|
-
* @example
|
|
729
|
-
* ```ts
|
|
730
|
-
* find(users, {}).skip(10).limit(10).toArray() // page 2
|
|
731
|
-
* ```
|
|
732
|
-
*/
|
|
733
|
-
skip(n: number): this;
|
|
734
|
-
/**
|
|
735
|
-
* Limit the number of documents returned.
|
|
736
|
-
*
|
|
737
|
-
* @param n - Maximum number of documents to return.
|
|
738
|
-
* @returns `this` for chaining.
|
|
739
|
-
*
|
|
740
|
-
* @example
|
|
741
|
-
* ```ts
|
|
742
|
-
* find(users, {}).limit(10).toArray() // at most 10 docs
|
|
743
|
-
* ```
|
|
744
|
-
*/
|
|
745
|
-
limit(n: number): this;
|
|
746
|
-
/**
|
|
747
|
-
* Force the query optimizer to use the specified index.
|
|
748
|
-
*
|
|
749
|
-
* Only accepts index names that were declared via `.name()` in the
|
|
750
|
-
* collection definition. If no named indexes exist, any string is accepted.
|
|
751
|
-
*
|
|
752
|
-
* @param indexName - The name of a declared compound index.
|
|
753
|
-
* @returns `this` for chaining.
|
|
754
|
-
*
|
|
755
|
-
* @example
|
|
756
|
-
* ```ts
|
|
757
|
-
* const Users = collection('users', { email: z.string(), role: z.string() }, {
|
|
758
|
-
* indexes: [index({ email: 1, role: -1 }).name('email_role_idx')],
|
|
759
|
-
* })
|
|
760
|
-
* const admins = await users.find({ role: 'admin' })
|
|
761
|
-
* .hint('email_role_idx')
|
|
762
|
-
* .toArray()
|
|
763
|
-
* ```
|
|
764
|
-
*/
|
|
765
|
-
hint(indexName: TIndexNames): this;
|
|
766
|
-
/**
|
|
767
|
-
* Execute the query with offset-based pagination, returning a page of documents
|
|
768
|
-
* with total count and navigation metadata.
|
|
769
|
-
*
|
|
770
|
-
* Runs `countDocuments` and `find` in parallel for performance. Ignores any
|
|
771
|
-
* `.skip()` or `.limit()` already set on the cursor — issues a fresh query.
|
|
772
|
-
*
|
|
773
|
-
* @param opts - Offset pagination options: `page` (1-indexed) and `perPage`.
|
|
774
|
-
* @returns A page with `docs`, `total`, `totalPages`, `hasNext`, `hasPrev`.
|
|
775
|
-
* @throws {ZodmonValidationError} When a document fails schema validation.
|
|
776
|
-
*
|
|
777
|
-
* @example
|
|
778
|
-
* ```ts
|
|
779
|
-
* const page = await users.find({ role: 'admin' })
|
|
780
|
-
* .sort({ createdAt: -1 })
|
|
781
|
-
* .paginate({ page: 2, perPage: 10 })
|
|
782
|
-
* console.log(page.total, page.totalPages, page.hasNext)
|
|
783
|
-
* ```
|
|
784
|
-
*/
|
|
785
|
-
paginate(opts: OffsetPaginateOptions): Promise<OffsetPage<InferDocument<TDef>>>;
|
|
786
|
-
/**
|
|
787
|
-
* Execute the query with cursor-based pagination, returning a page of documents
|
|
788
|
-
* with opaque cursors for forward/backward navigation.
|
|
789
|
-
*
|
|
790
|
-
* Uses the `limit + 1` trick to determine `hasNext`/`hasPrev` without extra queries.
|
|
791
|
-
* Direction is encoded in the cursor — pass `endCursor` to go forward, `startCursor`
|
|
792
|
-
* to go backward.
|
|
793
|
-
*
|
|
794
|
-
* @param opts - Cursor pagination options: `limit` and optional `cursor`.
|
|
795
|
-
* @returns A page with `docs`, `hasNext`, `hasPrev`, `startCursor`, `endCursor`.
|
|
796
|
-
* @throws {ZodmonValidationError} When a document fails schema validation.
|
|
797
|
-
* @throws {Error} When the cursor string is malformed.
|
|
798
|
-
*
|
|
799
|
-
* @example
|
|
800
|
-
* ```ts
|
|
801
|
-
* const first = await users.find({}).sort({ name: 1 }).paginate({ limit: 10 })
|
|
802
|
-
* const next = await users.find({}).sort({ name: 1 })
|
|
803
|
-
* .paginate({ cursor: first.endCursor, limit: 10 })
|
|
804
|
-
* ```
|
|
805
|
-
*/
|
|
806
|
-
paginate(opts: CursorPaginateOptions): Promise<CursorPage<InferDocument<TDef>>>;
|
|
807
|
-
/** @internal Offset pagination implementation. */
|
|
808
|
-
private offsetPaginate;
|
|
809
|
-
/** @internal Cursor pagination implementation. */
|
|
810
|
-
private cursorPaginate;
|
|
811
|
-
/**
|
|
812
|
-
* Execute the query and return all matching documents as an array.
|
|
813
|
-
*
|
|
814
|
-
* Each document is validated against the collection's Zod schema
|
|
815
|
-
* according to the resolved validation mode.
|
|
816
|
-
*
|
|
817
|
-
* @returns Array of validated documents.
|
|
818
|
-
* @throws {ZodmonValidationError} When a document fails schema validation in strict/strip mode.
|
|
819
|
-
*
|
|
820
|
-
* @example
|
|
821
|
-
* ```ts
|
|
822
|
-
* const admins = await find(users, { role: 'admin' }).toArray()
|
|
823
|
-
* ```
|
|
824
|
-
*/
|
|
825
|
-
toArray(): Promise<InferDocument<TDef>[]>;
|
|
826
|
-
/**
|
|
827
|
-
* Async iterator for streaming documents one at a time.
|
|
828
|
-
*
|
|
829
|
-
* Each yielded document is validated against the collection's Zod schema.
|
|
830
|
-
* Memory-efficient for large result sets.
|
|
831
|
-
*
|
|
832
|
-
* @yields Validated documents one at a time.
|
|
833
|
-
* @throws {ZodmonValidationError} When a document fails schema validation.
|
|
834
|
-
*
|
|
835
|
-
* @example
|
|
836
|
-
* ```ts
|
|
837
|
-
* for await (const user of find(users, {})) {
|
|
838
|
-
* console.log(user.name)
|
|
839
|
-
* }
|
|
840
|
-
* ```
|
|
841
|
-
*/
|
|
842
|
-
[Symbol.asyncIterator](): AsyncGenerator<InferDocument<TDef>>;
|
|
843
|
-
/** @internal Validate a single raw document against the schema. */
|
|
844
|
-
private validateDoc;
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
/**
|
|
848
|
-
* Options for {@link findOne} and {@link findOneOrThrow}.
|
|
849
|
-
*/
|
|
850
|
-
type FindOneOptions = {
|
|
851
|
-
/** MongoDB projection — include (`1`) or exclude (`0`) fields. Typed projections deferred to v1.0. */
|
|
852
|
-
project?: Record<string, 0 | 1>;
|
|
853
|
-
/** Override the collection-level validation mode, or `false` to skip validation entirely. */
|
|
854
|
-
validate?: ValidationMode | false;
|
|
855
|
-
};
|
|
791
|
+
declare const $avg: (field: `$${string}`) => Accumulator<number>;
|
|
856
792
|
/**
|
|
857
|
-
*
|
|
793
|
+
* Returns the minimum value across documents in each group.
|
|
858
794
|
*
|
|
859
|
-
*
|
|
860
|
-
*
|
|
861
|
-
* back to the collection-level default (which defaults to `'strict'`).
|
|
795
|
+
* For full type safety, prefer the callback builder (`acc.min('price')`).
|
|
796
|
+
* The standalone form accepts an explicit result type `R` for manual typing.
|
|
862
797
|
*
|
|
863
|
-
* @
|
|
864
|
-
* @param
|
|
865
|
-
* @
|
|
866
|
-
* @returns The matched document, or `null` if no document matches.
|
|
867
|
-
* @throws {ZodmonValidationError} When the fetched document fails schema validation in strict mode.
|
|
798
|
+
* @typeParam R - The expected result type (defaults to `unknown`).
|
|
799
|
+
* @param field - A `$field` reference.
|
|
800
|
+
* @returns An `Accumulator<R>`.
|
|
868
801
|
*
|
|
869
802
|
* @example
|
|
870
803
|
* ```ts
|
|
871
|
-
*
|
|
872
|
-
*
|
|
804
|
+
* // Tier 2 — explicit result type
|
|
805
|
+
* const pipeline = orders.aggregate()
|
|
806
|
+
* .groupBy('category', { cheapest: $min<number>('$price') })
|
|
807
|
+
*
|
|
808
|
+
* // Tier 1 — callback builder (recommended)
|
|
809
|
+
* orders.aggregate()
|
|
810
|
+
* .groupBy('category', acc => ({ cheapest: acc.min('price') }))
|
|
873
811
|
* ```
|
|
874
812
|
*/
|
|
875
|
-
declare
|
|
813
|
+
declare const $min: <R = unknown>(field: `$${string}`) => Accumulator<R>;
|
|
876
814
|
/**
|
|
877
|
-
*
|
|
815
|
+
* Returns the maximum value across documents in each group.
|
|
878
816
|
*
|
|
879
|
-
*
|
|
880
|
-
*
|
|
817
|
+
* For full type safety, prefer the callback builder (`acc.max('price')`).
|
|
818
|
+
* The standalone form accepts an explicit result type `R` for manual typing.
|
|
881
819
|
*
|
|
882
|
-
* @
|
|
883
|
-
* @param
|
|
884
|
-
* @
|
|
885
|
-
* @returns The matched document (never null).
|
|
886
|
-
* @throws {ZodmonNotFoundError} When no document matches the filter.
|
|
887
|
-
* @throws {ZodmonValidationError} When the fetched document fails schema validation in strict mode.
|
|
820
|
+
* @typeParam R - The expected result type (defaults to `unknown`).
|
|
821
|
+
* @param field - A `$field` reference.
|
|
822
|
+
* @returns An `Accumulator<R>`.
|
|
888
823
|
*
|
|
889
824
|
* @example
|
|
890
825
|
* ```ts
|
|
891
|
-
*
|
|
892
|
-
*
|
|
826
|
+
* // Tier 2 — explicit result type
|
|
827
|
+
* const pipeline = orders.aggregate()
|
|
828
|
+
* .groupBy('category', { priciest: $max<number>('$price') })
|
|
829
|
+
*
|
|
830
|
+
* // Tier 1 — callback builder (recommended)
|
|
831
|
+
* orders.aggregate()
|
|
832
|
+
* .groupBy('category', acc => ({ priciest: acc.max('price') }))
|
|
893
833
|
* ```
|
|
894
834
|
*/
|
|
895
|
-
declare
|
|
896
|
-
/**
|
|
897
|
-
* Options for {@link find}.
|
|
898
|
-
*/
|
|
899
|
-
type FindOptions = {
|
|
900
|
-
/** Override the collection-level validation mode, or `false` to skip validation entirely. */
|
|
901
|
-
validate?: ValidationMode | false;
|
|
902
|
-
};
|
|
835
|
+
declare const $max: <R = unknown>(field: `$${string}`) => Accumulator<R>;
|
|
903
836
|
/**
|
|
904
|
-
*
|
|
905
|
-
*
|
|
906
|
-
* The cursor is lazy — no query is executed until a terminal method
|
|
907
|
-
* (`toArray`, `for await`) is called. Use `sort`, `skip`, and `limit`
|
|
908
|
-
* to shape the query before executing.
|
|
837
|
+
* Returns the first value in each group according to the document order.
|
|
909
838
|
*
|
|
910
|
-
*
|
|
911
|
-
*
|
|
839
|
+
* For full type safety, prefer the callback builder (`acc.first('name')`).
|
|
840
|
+
* The standalone form accepts an explicit result type `R` for manual typing.
|
|
912
841
|
*
|
|
913
|
-
* @
|
|
914
|
-
* @param
|
|
915
|
-
* @
|
|
916
|
-
* @returns A typed cursor for chaining query modifiers.
|
|
842
|
+
* @typeParam R - The expected result type (defaults to `unknown`).
|
|
843
|
+
* @param field - A `$field` reference.
|
|
844
|
+
* @returns An `Accumulator<R>`.
|
|
917
845
|
*
|
|
918
846
|
* @example
|
|
919
847
|
* ```ts
|
|
920
|
-
*
|
|
921
|
-
*
|
|
922
|
-
*
|
|
923
|
-
*
|
|
924
|
-
* ```
|
|
848
|
+
* // Tier 2 — explicit result type
|
|
849
|
+
* const pipeline = orders.aggregate()
|
|
850
|
+
* .sort({ createdAt: 1 })
|
|
851
|
+
* .groupBy('status', { earliest: $first<Date>('$createdAt') })
|
|
925
852
|
*
|
|
926
|
-
*
|
|
927
|
-
*
|
|
928
|
-
*
|
|
929
|
-
*
|
|
930
|
-
* }
|
|
853
|
+
* // Tier 1 — callback builder (recommended)
|
|
854
|
+
* orders.aggregate()
|
|
855
|
+
* .sort({ createdAt: 1 })
|
|
856
|
+
* .groupBy('status', acc => ({ earliest: acc.first('createdAt') }))
|
|
931
857
|
* ```
|
|
932
858
|
*/
|
|
933
|
-
declare
|
|
934
|
-
|
|
859
|
+
declare const $first: <R = unknown>(field: `$${string}`) => Accumulator<R>;
|
|
935
860
|
/**
|
|
936
|
-
*
|
|
861
|
+
* Returns the last value in each group according to the document order.
|
|
937
862
|
*
|
|
938
|
-
*
|
|
939
|
-
*
|
|
940
|
-
* type E = ArrayElement<string[]> // string
|
|
941
|
-
* type N = ArrayElement<number[]> // number
|
|
942
|
-
* ```
|
|
943
|
-
*/
|
|
944
|
-
type ArrayElement<T> = T extends ReadonlyArray<infer E> ? E : never;
|
|
945
|
-
/**
|
|
946
|
-
* Fields valid for `$set`, `$setOnInsert`, `$min`, and `$max` operators.
|
|
863
|
+
* For full type safety, prefer the callback builder (`acc.last('name')`).
|
|
864
|
+
* The standalone form accepts an explicit result type `R` for manual typing.
|
|
947
865
|
*
|
|
948
|
-
*
|
|
949
|
-
*
|
|
866
|
+
* @typeParam R - The expected result type (defaults to `unknown`).
|
|
867
|
+
* @param field - A `$field` reference.
|
|
868
|
+
* @returns An `Accumulator<R>`.
|
|
950
869
|
*
|
|
951
870
|
* @example
|
|
952
871
|
* ```ts
|
|
953
|
-
*
|
|
872
|
+
* // Tier 2 — explicit result type
|
|
873
|
+
* const pipeline = orders.aggregate()
|
|
874
|
+
* .sort({ createdAt: -1 })
|
|
875
|
+
* .groupBy('status', { latest: $last<Date>('$createdAt') })
|
|
876
|
+
*
|
|
877
|
+
* // Tier 1 — callback builder (recommended)
|
|
878
|
+
* orders.aggregate()
|
|
879
|
+
* .sort({ createdAt: -1 })
|
|
880
|
+
* .groupBy('status', acc => ({ latest: acc.last('createdAt') }))
|
|
954
881
|
* ```
|
|
955
882
|
*/
|
|
956
|
-
|
|
957
|
-
[K in keyof T]?: T[K];
|
|
958
|
-
} & {
|
|
959
|
-
[P in DotPaths<T>]?: DotPathType<T, P>;
|
|
960
|
-
};
|
|
883
|
+
declare const $last: <R = unknown>(field: `$${string}`) => Accumulator<R>;
|
|
961
884
|
/**
|
|
962
|
-
*
|
|
885
|
+
* Pushes values into an array for each group.
|
|
963
886
|
*
|
|
964
|
-
*
|
|
887
|
+
* May contain duplicates. Use `$addToSet` for unique values.
|
|
888
|
+
* For full type safety, prefer the callback builder (`acc.push('name')`).
|
|
889
|
+
*
|
|
890
|
+
* @typeParam R - The element type (defaults to `unknown`).
|
|
891
|
+
* @param field - A `$field` reference.
|
|
892
|
+
* @returns An `Accumulator<R[]>`.
|
|
965
893
|
*
|
|
966
894
|
* @example
|
|
967
895
|
* ```ts
|
|
968
|
-
*
|
|
896
|
+
* // Tier 2 — explicit element type
|
|
897
|
+
* const pipeline = orders.aggregate()
|
|
898
|
+
* .groupBy('status', { items: $push<string>('$name') })
|
|
899
|
+
*
|
|
900
|
+
* // Tier 1 — callback builder (recommended)
|
|
901
|
+
* orders.aggregate()
|
|
902
|
+
* .groupBy('status', acc => ({ items: acc.push('name') }))
|
|
969
903
|
* ```
|
|
970
904
|
*/
|
|
971
|
-
|
|
972
|
-
[K in keyof T as NonNullable<T[K]> extends number ? K : never]?: number;
|
|
973
|
-
} & {
|
|
974
|
-
[P in DotPaths<T> as DotPathType<T, P> extends number ? P : never]?: number;
|
|
975
|
-
};
|
|
905
|
+
declare const $push: <R = unknown>(field: `$${string}`) => Accumulator<R[]>;
|
|
976
906
|
/**
|
|
977
|
-
*
|
|
907
|
+
* Collects unique values into an array for each group (set semantics).
|
|
978
908
|
*
|
|
979
|
-
*
|
|
909
|
+
* Like `$push` but deduplicates.
|
|
910
|
+
* For full type safety, prefer the callback builder (`acc.addToSet('tag')`).
|
|
911
|
+
*
|
|
912
|
+
* @typeParam R - The element type (defaults to `unknown`).
|
|
913
|
+
* @param field - A `$field` reference.
|
|
914
|
+
* @returns An `Accumulator<R[]>`.
|
|
980
915
|
*
|
|
981
916
|
* @example
|
|
982
917
|
* ```ts
|
|
983
|
-
*
|
|
918
|
+
* // Tier 2 — explicit element type
|
|
919
|
+
* const pipeline = orders.aggregate()
|
|
920
|
+
* .groupBy('category', { uniqueTags: $addToSet<string>('$tag') })
|
|
921
|
+
*
|
|
922
|
+
* // Tier 1 — callback builder (recommended)
|
|
923
|
+
* orders.aggregate()
|
|
924
|
+
* .groupBy('category', acc => ({ uniqueTags: acc.addToSet('tag') }))
|
|
984
925
|
* ```
|
|
985
926
|
*/
|
|
986
|
-
|
|
987
|
-
/** Array of elements to push. */
|
|
988
|
-
$each: E[];
|
|
989
|
-
/** Position at which to insert elements. */
|
|
990
|
-
$position?: number;
|
|
991
|
-
/** Maximum array length after push. */
|
|
992
|
-
$slice?: number;
|
|
993
|
-
/** Sort order applied after push. */
|
|
994
|
-
$sort?: 1 | -1 | Record<string, 1 | -1>;
|
|
995
|
-
};
|
|
927
|
+
declare const $addToSet: <R = unknown>(field: `$${string}`) => Accumulator<R[]>;
|
|
996
928
|
/**
|
|
997
|
-
*
|
|
929
|
+
* Create a typed accumulator builder for use inside `groupBy` callbacks.
|
|
998
930
|
*
|
|
999
|
-
*
|
|
931
|
+
* The builder adds the `$` prefix to field names automatically and returns
|
|
932
|
+
* properly typed `Accumulator<T[K]>` values. Primarily used internally by
|
|
933
|
+
* `AggregatePipeline.groupBy` — most users interact with the builder via
|
|
934
|
+
* the callback parameter rather than calling this directly.
|
|
935
|
+
*
|
|
936
|
+
* @typeParam T - The current pipeline output document type.
|
|
937
|
+
* @returns An `AccumulatorBuilder<T>` with methods for each MongoDB accumulator.
|
|
1000
938
|
*
|
|
1001
939
|
* @example
|
|
1002
940
|
* ```ts
|
|
1003
|
-
* const
|
|
1004
|
-
*
|
|
941
|
+
* const acc = createAccumulatorBuilder<{ salary: number; name: string }>()
|
|
942
|
+
* acc.min('salary') // { __accum: true, expr: { $min: '$salary' } }
|
|
943
|
+
* acc.push('name') // { __accum: true, expr: { $push: '$name' } }
|
|
1005
944
|
* ```
|
|
1006
945
|
*/
|
|
1007
|
-
|
|
1008
|
-
[K in keyof T as NonNullable<T[K]> extends ReadonlyArray<unknown> ? K : never]?: ArrayElement<NonNullable<T[K]>> | PushModifiers<ArrayElement<NonNullable<T[K]>>>;
|
|
1009
|
-
};
|
|
946
|
+
declare function createAccumulatorBuilder<T>(): AccumulatorBuilder<T>;
|
|
1010
947
|
/**
|
|
1011
|
-
*
|
|
948
|
+
* Create a typed expression builder for use inside `addFields` callbacks.
|
|
1012
949
|
*
|
|
1013
|
-
*
|
|
1014
|
-
*
|
|
950
|
+
* The builder adds the `$` prefix to field names automatically and returns
|
|
951
|
+
* properly typed `Expression<T>` values. Primarily used internally by
|
|
952
|
+
* `AggregatePipeline.addFields` — most users interact with the builder via
|
|
953
|
+
* the callback parameter rather than calling this directly.
|
|
1015
954
|
*
|
|
1016
|
-
* @
|
|
1017
|
-
*
|
|
1018
|
-
* const pull: PullFields<User> = { tags: 'old' }
|
|
1019
|
-
* const pullQuery: PullFields<User> = { scores: { $lt: 50 } }
|
|
1020
|
-
* const pullObj: PullFields<User> = { comments: { author: 'spam' } }
|
|
1021
|
-
* ```
|
|
1022
|
-
*/
|
|
1023
|
-
type PullFields<T> = {
|
|
1024
|
-
[K in keyof T as NonNullable<T[K]> extends ReadonlyArray<unknown> ? K : never]?: ArrayElement<NonNullable<T[K]>> | ComparisonOperators<ArrayElement<NonNullable<T[K]>>> | (ArrayElement<NonNullable<T[K]>> extends Record<string, unknown> ? TypedFilter<ArrayElement<NonNullable<T[K]>>> : unknown);
|
|
1025
|
-
};
|
|
1026
|
-
/**
|
|
1027
|
-
* Modifier for the `$addToSet` operator's `$each` syntax.
|
|
955
|
+
* @typeParam T - The current pipeline output document type.
|
|
956
|
+
* @returns An `ExpressionBuilder<T>` with methods for each MongoDB expression operator.
|
|
1028
957
|
*
|
|
1029
958
|
* @example
|
|
1030
959
|
* ```ts
|
|
1031
|
-
* const
|
|
960
|
+
* const expr = createExpressionBuilder<{ salary: number; name: string; hiredAt: Date }>()
|
|
961
|
+
* expr.year('hiredAt') // { __expr: true, value: { $year: '$hiredAt' } }
|
|
962
|
+
* expr.multiply('salary', 0.9) // { __expr: true, value: { $multiply: ['$salary', 0.9] } }
|
|
1032
963
|
* ```
|
|
1033
964
|
*/
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
};
|
|
965
|
+
declare function createExpressionBuilder<T>(): ExpressionBuilder<T>;
|
|
966
|
+
|
|
1037
967
|
/**
|
|
1038
|
-
*
|
|
968
|
+
* Comparison operators for a field value of type `V`.
|
|
1039
969
|
*
|
|
1040
|
-
*
|
|
970
|
+
* Maps each MongoDB comparison operator to its expected value type.
|
|
971
|
+
* `$regex` is only available when `V` extends `string`.
|
|
972
|
+
*
|
|
973
|
+
* Used as the operator object that can be assigned to a field in {@link TypedFilter}.
|
|
1041
974
|
*
|
|
1042
975
|
* @example
|
|
1043
976
|
* ```ts
|
|
1044
|
-
*
|
|
1045
|
-
* const
|
|
977
|
+
* // As a raw object (without builder functions)
|
|
978
|
+
* const filter: TypedFilter<User> = { age: { $gt: 25, $lte: 65 } }
|
|
979
|
+
*
|
|
980
|
+
* // $regex only available on string fields
|
|
981
|
+
* const filter: TypedFilter<User> = { name: { $regex: /^A/i } }
|
|
1046
982
|
* ```
|
|
1047
983
|
*/
|
|
1048
|
-
type
|
|
1049
|
-
|
|
1050
|
-
|
|
984
|
+
type ComparisonOperators<V> = {
|
|
985
|
+
/** Matches values equal to the specified value. */
|
|
986
|
+
$eq?: V;
|
|
987
|
+
/** Matches values not equal to the specified value. */
|
|
988
|
+
$ne?: V;
|
|
989
|
+
/** Matches values greater than the specified value. */
|
|
990
|
+
$gt?: V;
|
|
991
|
+
/** Matches values greater than or equal to the specified value. */
|
|
992
|
+
$gte?: V;
|
|
993
|
+
/** Matches values less than the specified value. */
|
|
994
|
+
$lt?: V;
|
|
995
|
+
/** Matches values less than or equal to the specified value. */
|
|
996
|
+
$lte?: V;
|
|
997
|
+
/** Matches any value in the specified array. Accepts `as const` arrays for type narrowing. */
|
|
998
|
+
$in?: readonly V[];
|
|
999
|
+
/** Matches none of the values in the specified array. Accepts `as const` arrays for type narrowing. */
|
|
1000
|
+
$nin?: readonly V[];
|
|
1001
|
+
/** Matches documents where the field exists (`true`) or does not exist (`false`). */
|
|
1002
|
+
$exists?: boolean;
|
|
1003
|
+
/** Negates a comparison operator. */
|
|
1004
|
+
$not?: ComparisonOperators<V>;
|
|
1005
|
+
} & (V extends string ? {
|
|
1006
|
+
$regex?: RegExp | string;
|
|
1007
|
+
} : unknown);
|
|
1008
|
+
/** Depth counter for limiting dot-notation recursion. Index = current depth, value = next depth. */
|
|
1009
|
+
type Prev = [never, 0, 1, 2];
|
|
1051
1010
|
/**
|
|
1052
|
-
*
|
|
1011
|
+
* Generates a union of all valid dot-separated paths for nested object fields in `T`.
|
|
1053
1012
|
*
|
|
1054
|
-
*
|
|
1013
|
+
* Recursion is limited to 3 levels deep to prevent TypeScript compilation performance issues.
|
|
1014
|
+
* Only plain object fields are traversed — arrays, `Date`, `RegExp`, and `ObjectId` are
|
|
1015
|
+
* treated as leaf nodes and do not produce sub-paths.
|
|
1055
1016
|
*
|
|
1056
1017
|
* @example
|
|
1057
1018
|
* ```ts
|
|
1058
|
-
*
|
|
1019
|
+
* type User = { address: { city: string; geo: { lat: number; lng: number } } }
|
|
1020
|
+
*
|
|
1021
|
+
* // DotPaths<User> = 'address.city' | 'address.geo' | 'address.geo.lat' | 'address.geo.lng'
|
|
1059
1022
|
* ```
|
|
1060
1023
|
*/
|
|
1061
|
-
type
|
|
1062
|
-
[K in keyof T
|
|
1063
|
-
};
|
|
1024
|
+
type DotPaths<T, Depth extends number = 3> = Depth extends 0 ? never : {
|
|
1025
|
+
[K in keyof T & string]: NonNullable<T[K]> extends ReadonlyArray<unknown> | Date | RegExp | ObjectId ? never : NonNullable<T[K]> extends Record<string, unknown> ? `${K}.${keyof NonNullable<T[K]> & string}` | `${K}.${DotPaths<NonNullable<T[K]>, Prev[Depth]>}` : never;
|
|
1026
|
+
}[keyof T & string];
|
|
1064
1027
|
/**
|
|
1065
|
-
*
|
|
1028
|
+
* Resolves the value type at a dot-separated path `P` within type `T`.
|
|
1066
1029
|
*
|
|
1067
|
-
*
|
|
1030
|
+
* Splits `P` on the first `.` and recursively descends into `T`'s nested types.
|
|
1031
|
+
* Returns `never` if the path is invalid.
|
|
1068
1032
|
*
|
|
1069
1033
|
* @example
|
|
1070
1034
|
* ```ts
|
|
1071
|
-
*
|
|
1035
|
+
* type User = { address: { city: string; geo: { lat: number } } }
|
|
1036
|
+
*
|
|
1037
|
+
* // DotPathType<User, 'address.city'> = string
|
|
1038
|
+
* // DotPathType<User, 'address.geo.lat'> = number
|
|
1072
1039
|
* ```
|
|
1073
1040
|
*/
|
|
1074
|
-
type
|
|
1075
|
-
[K in keyof T]?: '' | true | 1;
|
|
1076
|
-
};
|
|
1041
|
+
type DotPathType<T, P extends string> = P extends `${infer K}.${infer Rest}` ? K extends keyof T ? Rest extends keyof NonNullable<T[K]> ? NonNullable<T[K]>[Rest] : DotPathType<NonNullable<T[K]>, Rest> : never : P extends keyof T ? T[P] : never;
|
|
1077
1042
|
/**
|
|
1078
|
-
*
|
|
1043
|
+
* Strict type-safe MongoDB filter query type.
|
|
1079
1044
|
*
|
|
1080
|
-
*
|
|
1045
|
+
* Validates filter objects at compile time — rejects nonexistent fields, type mismatches,
|
|
1046
|
+
* and invalid operator usage. Unlike the MongoDB driver's `Filter<T>`, does NOT allow
|
|
1047
|
+
* arbitrary keys via `& Document`.
|
|
1081
1048
|
*
|
|
1082
|
-
*
|
|
1083
|
-
*
|
|
1084
|
-
*
|
|
1085
|
-
*
|
|
1086
|
-
*/
|
|
1087
|
-
type CurrentDateFields<T> = {
|
|
1088
|
-
[K in keyof T as NonNullable<T[K]> extends Date ? K : never]?: true | {
|
|
1089
|
-
$type: 'date';
|
|
1090
|
-
};
|
|
1091
|
-
};
|
|
1092
|
-
/**
|
|
1093
|
-
* Fields valid for the `$rename` operator.
|
|
1049
|
+
* Supports three forms of filter expressions:
|
|
1050
|
+
* - **Direct field values** (implicit `$eq`): `{ name: 'Alice' }`
|
|
1051
|
+
* - **Comparison operators**: `{ age: { $gt: 25 } }` or `{ age: $gt(25) }`
|
|
1052
|
+
* - **Dot notation** for nested fields up to 3 levels: `{ 'address.city': 'NYC' }`
|
|
1094
1053
|
*
|
|
1095
|
-
*
|
|
1096
|
-
*
|
|
1054
|
+
* Logical operators `$and`, `$or`, and `$nor` accept arrays of `TypedFilter<T>`
|
|
1055
|
+
* for composing complex queries.
|
|
1097
1056
|
*
|
|
1098
1057
|
* @example
|
|
1099
1058
|
* ```ts
|
|
1100
|
-
*
|
|
1101
|
-
*
|
|
1102
|
-
*/
|
|
1103
|
-
type RenameFields<T> = {
|
|
1104
|
-
[K in keyof T & string]?: string;
|
|
1105
|
-
};
|
|
1106
|
-
/**
|
|
1107
|
-
* Strict type-safe MongoDB update filter.
|
|
1108
|
-
*
|
|
1109
|
-
* Validates update operators against field types at compile time. Each operator
|
|
1110
|
-
* constrains which fields it accepts (e.g. `$inc` only on numbers, `$push` only
|
|
1111
|
-
* on arrays). Supports dot-notation paths for nested field access.
|
|
1059
|
+
* // Simple equality
|
|
1060
|
+
* const filter: TypedFilter<User> = { name: 'Alice' }
|
|
1112
1061
|
*
|
|
1113
|
-
*
|
|
1114
|
-
*
|
|
1115
|
-
*
|
|
1116
|
-
*
|
|
1117
|
-
*
|
|
1118
|
-
* }
|
|
1062
|
+
* // Builder functions mixed with object literals
|
|
1063
|
+
* const filter: TypedFilter<User> = { age: $gte(18), role: $in(['admin', 'mod']) }
|
|
1064
|
+
*
|
|
1065
|
+
* // Logical composition — T inferred from find() context
|
|
1066
|
+
* posts.find($and(
|
|
1067
|
+
* $or({ published: true }, { views: $gte(100) }),
|
|
1068
|
+
* { title: $regex(/guide/i) },
|
|
1069
|
+
* ))
|
|
1070
|
+
*
|
|
1071
|
+
* // Dynamic conditional building
|
|
1072
|
+
* const conditions: TypedFilter<User>[] = []
|
|
1073
|
+
* if (name) conditions.push({ name })
|
|
1074
|
+
* if (minAge) conditions.push({ age: $gte(minAge) })
|
|
1075
|
+
* const filter = conditions.length ? $and<User>(...conditions) : {}
|
|
1119
1076
|
* ```
|
|
1120
1077
|
*/
|
|
1121
|
-
type
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
/**
|
|
1127
|
-
$
|
|
1128
|
-
/**
|
|
1129
|
-
$
|
|
1130
|
-
/**
|
|
1131
|
-
$
|
|
1132
|
-
/** Appends a value to an array field. Supports `$each`, `$position`, `$slice`, `$sort`. */
|
|
1133
|
-
$push?: PushFields<T>;
|
|
1134
|
-
/** Removes matching values from an array field. */
|
|
1135
|
-
$pull?: PullFields<T>;
|
|
1136
|
-
/** Adds a value to an array only if it doesn't already exist. */
|
|
1137
|
-
$addToSet?: AddToSetFields<T>;
|
|
1138
|
-
/** Removes the first (`-1`) or last (`1`) element of an array. */
|
|
1139
|
-
$pop?: PopFields<T>;
|
|
1140
|
-
/** Removes the specified fields from the document. */
|
|
1141
|
-
$unset?: UnsetFields<T>;
|
|
1142
|
-
/** Sets the field to the current date. Only accepts Date-typed fields. */
|
|
1143
|
-
$currentDate?: CurrentDateFields<T>;
|
|
1144
|
-
/** Renames a field. */
|
|
1145
|
-
$rename?: RenameFields<T>;
|
|
1078
|
+
type TypedFilter<T> = {
|
|
1079
|
+
[K in keyof T]?: T[K] | ComparisonOperators<T[K]>;
|
|
1080
|
+
} & {
|
|
1081
|
+
[P in DotPaths<T>]?: DotPathType<T, P> | ComparisonOperators<DotPathType<T, P>>;
|
|
1082
|
+
} & {
|
|
1083
|
+
/** Joins clauses with a logical AND. Matches documents that satisfy all filters. */
|
|
1084
|
+
$and?: TypedFilter<T>[];
|
|
1085
|
+
/** Joins clauses with a logical OR. Matches documents that satisfy at least one filter. */
|
|
1086
|
+
$or?: TypedFilter<T>[];
|
|
1087
|
+
/** Joins clauses with a logical NOR. Matches documents that fail all filters. */
|
|
1088
|
+
$nor?: TypedFilter<T>[];
|
|
1146
1089
|
};
|
|
1147
1090
|
|
|
1148
1091
|
/**
|
|
1149
|
-
* Options for {@link
|
|
1150
|
-
*/
|
|
1151
|
-
type UpdateOptions = {
|
|
1152
|
-
/** When `true`, inserts a new document if no document matches the filter. */
|
|
1153
|
-
upsert?: boolean;
|
|
1154
|
-
};
|
|
1155
|
-
/**
|
|
1156
|
-
* Options for {@link findOneAndUpdate}.
|
|
1092
|
+
* Options for {@link findOneAndDelete}.
|
|
1157
1093
|
*/
|
|
1158
|
-
type
|
|
1159
|
-
/** Whether to return the document before or after the update. Defaults to `'after'`. */
|
|
1160
|
-
returnDocument?: 'before' | 'after';
|
|
1161
|
-
/** When `true`, inserts a new document if no document matches the filter. */
|
|
1162
|
-
upsert?: boolean;
|
|
1094
|
+
type FindOneAndDeleteOptions = {
|
|
1163
1095
|
/** Override the collection-level validation mode, or `false` to skip validation entirely. */
|
|
1164
1096
|
validate?: ValidationMode | false;
|
|
1165
1097
|
};
|
|
1166
1098
|
/**
|
|
1167
|
-
*
|
|
1099
|
+
* Delete a single document matching the filter.
|
|
1168
1100
|
*
|
|
1169
|
-
*
|
|
1170
|
-
*
|
|
1171
|
-
*
|
|
1101
|
+
* Removes the first document that matches the filter from the collection.
|
|
1102
|
+
* No validation is performed — the document is deleted directly through
|
|
1103
|
+
* the MongoDB driver.
|
|
1172
1104
|
*
|
|
1173
|
-
* @param handle - The collection handle to
|
|
1105
|
+
* @param handle - The collection handle to delete from.
|
|
1174
1106
|
* @param filter - Type-safe filter to match documents.
|
|
1175
|
-
* @
|
|
1176
|
-
* @param options - Optional settings such as `upsert`.
|
|
1177
|
-
* @returns The MongoDB `UpdateResult` with match/modify counts.
|
|
1107
|
+
* @returns The MongoDB `DeleteResult` with the deleted count.
|
|
1178
1108
|
*
|
|
1179
1109
|
* @example
|
|
1180
1110
|
* ```ts
|
|
1181
|
-
* const result = await
|
|
1182
|
-
* console.log(result.
|
|
1111
|
+
* const result = await deleteOne(users, { name: 'Ada' })
|
|
1112
|
+
* console.log(result.deletedCount) // 1
|
|
1183
1113
|
* ```
|
|
1184
1114
|
*/
|
|
1185
|
-
declare function
|
|
1115
|
+
declare function deleteOne<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>): Promise<DeleteResult>;
|
|
1186
1116
|
/**
|
|
1187
|
-
*
|
|
1117
|
+
* Delete all documents matching the filter.
|
|
1188
1118
|
*
|
|
1189
|
-
*
|
|
1190
|
-
*
|
|
1191
|
-
*
|
|
1119
|
+
* Removes every document that matches the filter from the collection.
|
|
1120
|
+
* No validation is performed — documents are deleted directly through
|
|
1121
|
+
* the MongoDB driver.
|
|
1192
1122
|
*
|
|
1193
|
-
* @param handle - The collection handle to
|
|
1123
|
+
* @param handle - The collection handle to delete from.
|
|
1194
1124
|
* @param filter - Type-safe filter to match documents.
|
|
1195
|
-
* @
|
|
1196
|
-
* @param options - Optional settings such as `upsert`.
|
|
1197
|
-
* @returns The MongoDB `UpdateResult` with match/modify counts.
|
|
1125
|
+
* @returns The MongoDB `DeleteResult` with the deleted count.
|
|
1198
1126
|
*
|
|
1199
1127
|
* @example
|
|
1200
1128
|
* ```ts
|
|
1201
|
-
* const result = await
|
|
1202
|
-
* console.log(result.
|
|
1129
|
+
* const result = await deleteMany(users, { role: 'guest' })
|
|
1130
|
+
* console.log(result.deletedCount) // number of guests removed
|
|
1203
1131
|
* ```
|
|
1204
1132
|
*/
|
|
1205
|
-
declare function
|
|
1133
|
+
declare function deleteMany<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>): Promise<DeleteResult>;
|
|
1206
1134
|
/**
|
|
1207
|
-
* Find a single document matching the filter,
|
|
1135
|
+
* Find a single document matching the filter, delete it, and return the document.
|
|
1208
1136
|
*
|
|
1209
|
-
*
|
|
1210
|
-
*
|
|
1211
|
-
*
|
|
1212
|
-
* resolution logic as {@link findOne}.
|
|
1137
|
+
* Returns the deleted document, or `null` if no document matches the filter.
|
|
1138
|
+
* The returned document is validated against the collection's Zod schema
|
|
1139
|
+
* using the same resolution logic as {@link findOne}.
|
|
1213
1140
|
*
|
|
1214
|
-
* @param handle - The collection handle to
|
|
1141
|
+
* @param handle - The collection handle to delete from.
|
|
1215
1142
|
* @param filter - Type-safe filter to match documents.
|
|
1216
|
-
* @param
|
|
1217
|
-
* @
|
|
1218
|
-
* @returns The matched document (before or after update), or `null` if no document matches.
|
|
1143
|
+
* @param options - Optional settings: `validate`.
|
|
1144
|
+
* @returns The deleted document, or `null` if no document matches.
|
|
1219
1145
|
* @throws {ZodmonValidationError} When the returned document fails schema validation in strict mode.
|
|
1220
1146
|
*
|
|
1221
1147
|
* @example
|
|
1222
1148
|
* ```ts
|
|
1223
|
-
* const user = await
|
|
1224
|
-
*
|
|
1225
|
-
* { name: 'Ada' },
|
|
1226
|
-
* { $set: { role: 'admin' } },
|
|
1227
|
-
* )
|
|
1228
|
-
* if (user) console.log(user.role) // 'admin' (returned after update)
|
|
1149
|
+
* const user = await findOneAndDelete(users, { name: 'Ada' })
|
|
1150
|
+
* if (user) console.log(user.name) // 'Ada' (the deleted document)
|
|
1229
1151
|
* ```
|
|
1230
1152
|
*
|
|
1231
1153
|
* @example
|
|
1232
1154
|
* ```ts
|
|
1233
|
-
* const
|
|
1155
|
+
* const user = await findOneAndDelete(
|
|
1234
1156
|
* users,
|
|
1235
|
-
* {
|
|
1236
|
-
* {
|
|
1237
|
-
* { returnDocument: 'before' },
|
|
1157
|
+
* { role: 'guest' },
|
|
1158
|
+
* { validate: false },
|
|
1238
1159
|
* )
|
|
1239
1160
|
* ```
|
|
1240
1161
|
*/
|
|
1241
|
-
declare function
|
|
1162
|
+
declare function findOneAndDelete<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, options?: FindOneAndDeleteOptions): Promise<InferDocument<TDef> | null>;
|
|
1242
1163
|
|
|
1243
1164
|
/**
|
|
1244
|
-
*
|
|
1165
|
+
* Options for offset-based pagination.
|
|
1245
1166
|
*
|
|
1246
|
-
*
|
|
1247
|
-
*
|
|
1248
|
-
*
|
|
1167
|
+
* @example
|
|
1168
|
+
* ```ts
|
|
1169
|
+
* await users.find({}).sort({ name: 1 }).paginate({ page: 2, perPage: 10 })
|
|
1170
|
+
* ```
|
|
1171
|
+
*/
|
|
1172
|
+
type OffsetPaginateOptions = {
|
|
1173
|
+
/** The page number to retrieve (1-indexed). */
|
|
1174
|
+
page: number;
|
|
1175
|
+
/** The number of documents per page. */
|
|
1176
|
+
perPage: number;
|
|
1177
|
+
};
|
|
1178
|
+
/**
|
|
1179
|
+
* Options for cursor-based pagination.
|
|
1249
1180
|
*
|
|
1250
|
-
* @
|
|
1251
|
-
*
|
|
1181
|
+
* @example
|
|
1182
|
+
* ```ts
|
|
1183
|
+
* const first = await users.find({}).sort({ name: 1 }).paginate({ limit: 10 })
|
|
1184
|
+
* const next = await users.find({}).sort({ name: 1 }).paginate({ cursor: first.endCursor, limit: 10 })
|
|
1185
|
+
* ```
|
|
1252
1186
|
*/
|
|
1253
|
-
|
|
1254
|
-
/**
|
|
1255
|
-
|
|
1256
|
-
/**
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
/**
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1187
|
+
type CursorPaginateOptions = {
|
|
1188
|
+
/** Maximum number of documents to return. */
|
|
1189
|
+
limit: number;
|
|
1190
|
+
/** Opaque cursor string from a previous `startCursor` or `endCursor`. */
|
|
1191
|
+
cursor?: string | null;
|
|
1192
|
+
};
|
|
1193
|
+
/**
|
|
1194
|
+
* Result of offset-based pagination.
|
|
1195
|
+
*
|
|
1196
|
+
* @example
|
|
1197
|
+
* ```ts
|
|
1198
|
+
* const page = await users.find({}).paginate({ page: 1, perPage: 10 })
|
|
1199
|
+
* console.log(page.total, page.totalPages, page.hasNext)
|
|
1200
|
+
* ```
|
|
1201
|
+
*/
|
|
1202
|
+
type OffsetPage<TDoc> = {
|
|
1203
|
+
/** The documents for this page. */
|
|
1204
|
+
docs: TDoc[];
|
|
1205
|
+
/** Total number of matching documents. */
|
|
1206
|
+
total: number;
|
|
1207
|
+
/** Current page number (1-indexed). */
|
|
1208
|
+
page: number;
|
|
1209
|
+
/** Number of documents per page. */
|
|
1210
|
+
perPage: number;
|
|
1211
|
+
/** Total number of pages (`Math.ceil(total / perPage)`). */
|
|
1212
|
+
totalPages: number;
|
|
1213
|
+
/** Whether there is a next page. */
|
|
1214
|
+
hasNext: boolean;
|
|
1215
|
+
/** Whether there is a previous page. */
|
|
1216
|
+
hasPrev: boolean;
|
|
1217
|
+
};
|
|
1218
|
+
/**
|
|
1219
|
+
* Result of cursor-based pagination.
|
|
1220
|
+
*
|
|
1221
|
+
* @example
|
|
1222
|
+
* ```ts
|
|
1223
|
+
* const page = await users.find({}).paginate({ limit: 10 })
|
|
1224
|
+
* if (page.hasNext) {
|
|
1225
|
+
* const next = await users.find({}).paginate({ cursor: page.endCursor, limit: 10 })
|
|
1226
|
+
* }
|
|
1227
|
+
* ```
|
|
1228
|
+
*/
|
|
1229
|
+
type CursorPage<TDoc> = {
|
|
1230
|
+
/** The documents for this page. */
|
|
1231
|
+
docs: TDoc[];
|
|
1232
|
+
/** Whether there are more documents after this page. */
|
|
1233
|
+
hasNext: boolean;
|
|
1234
|
+
/** Whether there are documents before this page. */
|
|
1235
|
+
hasPrev: boolean;
|
|
1236
|
+
/** Cursor for the first document (pass to `cursor` to go backward). `null` when empty. */
|
|
1237
|
+
startCursor: string | null;
|
|
1238
|
+
/** Cursor for the last document (pass to `cursor` to go forward). `null` when empty. */
|
|
1239
|
+
endCursor: string | null;
|
|
1240
|
+
};
|
|
1241
|
+
|
|
1242
|
+
/**
|
|
1243
|
+
* Type-safe sort specification for a document type.
|
|
1244
|
+
*
|
|
1245
|
+
* Constrains sort keys to top-level fields of `T` with direction `1` (ascending)
|
|
1246
|
+
* or `-1` (descending). Dot-path sorts deferred to v1.0.
|
|
1247
|
+
*
|
|
1248
|
+
* @example
|
|
1249
|
+
* ```ts
|
|
1250
|
+
* const sort: TypedSort<User> = { name: 1, createdAt: -1 }
|
|
1251
|
+
* ```
|
|
1252
|
+
*/
|
|
1253
|
+
type TypedSort<T> = Partial<Record<keyof T & string, 1 | -1>>;
|
|
1254
|
+
/**
|
|
1255
|
+
* Type-safe cursor wrapping MongoDB's `FindCursor`.
|
|
1256
|
+
*
|
|
1257
|
+
* Provides chainable query modifiers (`sort`, `skip`, `limit`, `hint`) that return
|
|
1258
|
+
* `this` for fluent chaining, and terminal methods (`toArray`,
|
|
1259
|
+
* `[Symbol.asyncIterator]`) that validate each document against the
|
|
1260
|
+
* collection's Zod schema before returning.
|
|
1261
|
+
*
|
|
1262
|
+
* Created by {@link find} — do not construct directly.
|
|
1263
|
+
*
|
|
1264
|
+
* @typeParam TDef - The collection definition type, used to infer the document type.
|
|
1265
|
+
* @typeParam TIndexNames - Union of declared index names accepted by `.hint()`.
|
|
1266
|
+
*
|
|
1267
|
+
* @example
|
|
1268
|
+
* ```ts
|
|
1269
|
+
* const docs = await find(users, { role: 'admin' })
|
|
1270
|
+
* .sort({ name: 1 })
|
|
1271
|
+
* .limit(10)
|
|
1272
|
+
* .toArray()
|
|
1273
|
+
* ```
|
|
1274
|
+
*/
|
|
1275
|
+
declare class TypedFindCursor<TDef extends AnyCollection, TIndexNames extends string = string> {
|
|
1276
|
+
/** @internal */
|
|
1277
|
+
private cursor;
|
|
1278
|
+
/** @internal */
|
|
1279
|
+
private schema;
|
|
1280
|
+
/** @internal */
|
|
1281
|
+
private collectionName;
|
|
1282
|
+
/** @internal */
|
|
1283
|
+
private mode;
|
|
1284
|
+
/** @internal */
|
|
1285
|
+
private readonly nativeCollection;
|
|
1286
|
+
/** @internal */
|
|
1287
|
+
private readonly filter;
|
|
1288
|
+
/** @internal */
|
|
1289
|
+
private sortSpec;
|
|
1290
|
+
/** @internal */
|
|
1291
|
+
constructor(cursor: FindCursor<InferDocument<TDef>>, definition: TDef, mode: ValidationMode | false, nativeCollection: Collection<InferDocument<TDef>>, filter: any);
|
|
1292
|
+
/**
|
|
1293
|
+
* Set the sort order for the query.
|
|
1294
|
+
*
|
|
1295
|
+
* Only top-level document fields are accepted as sort keys.
|
|
1296
|
+
* Values must be `1` (ascending) or `-1` (descending).
|
|
1297
|
+
*
|
|
1298
|
+
* @param spec - Sort specification mapping field names to sort direction.
|
|
1299
|
+
* @returns `this` for chaining.
|
|
1300
|
+
*
|
|
1301
|
+
* @example
|
|
1302
|
+
* ```ts
|
|
1303
|
+
* find(users, {}).sort({ name: 1, age: -1 }).toArray()
|
|
1304
|
+
* ```
|
|
1305
|
+
*/
|
|
1306
|
+
sort(spec: TypedSort<InferDocument<TDef>>): this;
|
|
1307
|
+
/**
|
|
1308
|
+
* Skip the first `n` documents in the result set.
|
|
1309
|
+
*
|
|
1310
|
+
* @param n - Number of documents to skip.
|
|
1311
|
+
* @returns `this` for chaining.
|
|
1312
|
+
*
|
|
1313
|
+
* @example
|
|
1314
|
+
* ```ts
|
|
1315
|
+
* find(users, {}).skip(10).limit(10).toArray() // page 2
|
|
1316
|
+
* ```
|
|
1317
|
+
*/
|
|
1318
|
+
skip(n: number): this;
|
|
1319
|
+
/**
|
|
1320
|
+
* Limit the number of documents returned.
|
|
1321
|
+
*
|
|
1322
|
+
* @param n - Maximum number of documents to return.
|
|
1323
|
+
* @returns `this` for chaining.
|
|
1324
|
+
*
|
|
1325
|
+
* @example
|
|
1326
|
+
* ```ts
|
|
1327
|
+
* find(users, {}).limit(10).toArray() // at most 10 docs
|
|
1328
|
+
* ```
|
|
1329
|
+
*/
|
|
1330
|
+
limit(n: number): this;
|
|
1331
|
+
/**
|
|
1332
|
+
* Force the query optimizer to use the specified index.
|
|
1333
|
+
*
|
|
1334
|
+
* Only accepts index names that were declared via `.name()` in the
|
|
1335
|
+
* collection definition. If no named indexes exist, any string is accepted.
|
|
1336
|
+
*
|
|
1337
|
+
* @param indexName - The name of a declared compound index.
|
|
1338
|
+
* @returns `this` for chaining.
|
|
1339
|
+
*
|
|
1340
|
+
* @example
|
|
1341
|
+
* ```ts
|
|
1342
|
+
* const Users = collection('users', { email: z.string(), role: z.string() }, {
|
|
1343
|
+
* indexes: [index({ email: 1, role: -1 }).name('email_role_idx')],
|
|
1344
|
+
* })
|
|
1345
|
+
* const admins = await users.find({ role: 'admin' })
|
|
1346
|
+
* .hint('email_role_idx')
|
|
1347
|
+
* .toArray()
|
|
1348
|
+
* ```
|
|
1349
|
+
*/
|
|
1350
|
+
hint(indexName: TIndexNames): this;
|
|
1351
|
+
/**
|
|
1352
|
+
* Execute the query with offset-based pagination, returning a page of documents
|
|
1353
|
+
* with total count and navigation metadata.
|
|
1354
|
+
*
|
|
1355
|
+
* Runs `countDocuments` and `find` in parallel for performance. Ignores any
|
|
1356
|
+
* `.skip()` or `.limit()` already set on the cursor — issues a fresh query.
|
|
1357
|
+
*
|
|
1358
|
+
* @param opts - Offset pagination options: `page` (1-indexed) and `perPage`.
|
|
1359
|
+
* @returns A page with `docs`, `total`, `totalPages`, `hasNext`, `hasPrev`.
|
|
1360
|
+
* @throws {ZodmonValidationError} When a document fails schema validation.
|
|
1361
|
+
*
|
|
1362
|
+
* @example
|
|
1363
|
+
* ```ts
|
|
1364
|
+
* const page = await users.find({ role: 'admin' })
|
|
1365
|
+
* .sort({ createdAt: -1 })
|
|
1366
|
+
* .paginate({ page: 2, perPage: 10 })
|
|
1367
|
+
* console.log(page.total, page.totalPages, page.hasNext)
|
|
1368
|
+
* ```
|
|
1369
|
+
*/
|
|
1370
|
+
paginate(opts: OffsetPaginateOptions): Promise<OffsetPage<InferDocument<TDef>>>;
|
|
1371
|
+
/**
|
|
1372
|
+
* Execute the query with cursor-based pagination, returning a page of documents
|
|
1373
|
+
* with opaque cursors for forward/backward navigation.
|
|
1374
|
+
*
|
|
1375
|
+
* Uses the `limit + 1` trick to determine `hasNext`/`hasPrev` without extra queries.
|
|
1376
|
+
* Direction is encoded in the cursor — pass `endCursor` to go forward, `startCursor`
|
|
1377
|
+
* to go backward.
|
|
1378
|
+
*
|
|
1379
|
+
* @param opts - Cursor pagination options: `limit` and optional `cursor`.
|
|
1380
|
+
* @returns A page with `docs`, `hasNext`, `hasPrev`, `startCursor`, `endCursor`.
|
|
1381
|
+
* @throws {ZodmonValidationError} When a document fails schema validation.
|
|
1382
|
+
* @throws {Error} When the cursor string is malformed.
|
|
1383
|
+
*
|
|
1384
|
+
* @example
|
|
1385
|
+
* ```ts
|
|
1386
|
+
* const first = await users.find({}).sort({ name: 1 }).paginate({ limit: 10 })
|
|
1387
|
+
* const next = await users.find({}).sort({ name: 1 })
|
|
1388
|
+
* .paginate({ cursor: first.endCursor, limit: 10 })
|
|
1389
|
+
* ```
|
|
1390
|
+
*/
|
|
1391
|
+
paginate(opts: CursorPaginateOptions): Promise<CursorPage<InferDocument<TDef>>>;
|
|
1392
|
+
/** @internal Offset pagination implementation. */
|
|
1393
|
+
private offsetPaginate;
|
|
1394
|
+
/** @internal Cursor pagination implementation. */
|
|
1395
|
+
private cursorPaginate;
|
|
1396
|
+
/**
|
|
1397
|
+
* Execute the query and return all matching documents as an array.
|
|
1398
|
+
*
|
|
1399
|
+
* Each document is validated against the collection's Zod schema
|
|
1400
|
+
* according to the resolved validation mode.
|
|
1401
|
+
*
|
|
1402
|
+
* @returns Array of validated documents.
|
|
1403
|
+
* @throws {ZodmonValidationError} When a document fails schema validation in strict/strip mode.
|
|
1404
|
+
*
|
|
1405
|
+
* @example
|
|
1406
|
+
* ```ts
|
|
1407
|
+
* const admins = await find(users, { role: 'admin' }).toArray()
|
|
1408
|
+
* ```
|
|
1409
|
+
*/
|
|
1410
|
+
toArray(): Promise<InferDocument<TDef>[]>;
|
|
1411
|
+
/**
|
|
1412
|
+
* Async iterator for streaming documents one at a time.
|
|
1413
|
+
*
|
|
1414
|
+
* Each yielded document is validated against the collection's Zod schema.
|
|
1415
|
+
* Memory-efficient for large result sets.
|
|
1416
|
+
*
|
|
1417
|
+
* @yields Validated documents one at a time.
|
|
1418
|
+
* @throws {ZodmonValidationError} When a document fails schema validation.
|
|
1419
|
+
*
|
|
1420
|
+
* @example
|
|
1421
|
+
* ```ts
|
|
1422
|
+
* for await (const user of find(users, {})) {
|
|
1423
|
+
* console.log(user.name)
|
|
1424
|
+
* }
|
|
1425
|
+
* ```
|
|
1426
|
+
*/
|
|
1427
|
+
[Symbol.asyncIterator](): AsyncGenerator<InferDocument<TDef>>;
|
|
1428
|
+
/** @internal Validate a single raw document against the schema. */
|
|
1429
|
+
private validateDoc;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
/**
|
|
1433
|
+
* Options for {@link findOne} and {@link findOneOrThrow}.
|
|
1434
|
+
*/
|
|
1435
|
+
type FindOneOptions = {
|
|
1436
|
+
/** MongoDB projection — include (`1`) or exclude (`0`) fields. Typed projections deferred to v1.0. */
|
|
1437
|
+
project?: Record<string, 0 | 1>;
|
|
1438
|
+
/** Override the collection-level validation mode, or `false` to skip validation entirely. */
|
|
1439
|
+
validate?: ValidationMode | false;
|
|
1440
|
+
};
|
|
1441
|
+
/**
|
|
1442
|
+
* Find a single document matching the filter.
|
|
1443
|
+
*
|
|
1444
|
+
* Queries MongoDB, then validates the fetched document against the collection's
|
|
1445
|
+
* Zod schema. Validation mode is resolved from the per-query option, falling
|
|
1446
|
+
* back to the collection-level default (which defaults to `'strict'`).
|
|
1447
|
+
*
|
|
1448
|
+
* @param handle - The collection handle to query.
|
|
1449
|
+
* @param filter - Type-safe filter to match documents.
|
|
1450
|
+
* @param options - Optional projection and validation overrides.
|
|
1451
|
+
* @returns The matched document, or `null` if no document matches.
|
|
1452
|
+
* @throws {ZodmonValidationError} When the fetched document fails schema validation in strict mode.
|
|
1453
|
+
*
|
|
1454
|
+
* @example
|
|
1455
|
+
* ```ts
|
|
1456
|
+
* const user = await findOne(users, { name: 'Ada' })
|
|
1457
|
+
* if (user) console.log(user.role) // typed as 'admin' | 'user'
|
|
1458
|
+
* ```
|
|
1459
|
+
*/
|
|
1460
|
+
declare function findOne<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, options?: FindOneOptions): Promise<InferDocument<TDef> | null>;
|
|
1461
|
+
/**
|
|
1462
|
+
* Find a single document matching the filter, or throw if none exists.
|
|
1463
|
+
*
|
|
1464
|
+
* Behaves identically to {@link findOne} but throws {@link ZodmonNotFoundError}
|
|
1465
|
+
* instead of returning `null` when no document matches the filter.
|
|
1466
|
+
*
|
|
1467
|
+
* @param handle - The collection handle to query.
|
|
1468
|
+
* @param filter - Type-safe filter to match documents.
|
|
1469
|
+
* @param options - Optional projection and validation overrides.
|
|
1470
|
+
* @returns The matched document (never null).
|
|
1471
|
+
* @throws {ZodmonNotFoundError} When no document matches the filter.
|
|
1472
|
+
* @throws {ZodmonValidationError} When the fetched document fails schema validation in strict mode.
|
|
1473
|
+
*
|
|
1474
|
+
* @example
|
|
1475
|
+
* ```ts
|
|
1476
|
+
* const user = await findOneOrThrow(users, { name: 'Ada' })
|
|
1477
|
+
* console.log(user.role) // typed as 'admin' | 'user', guaranteed non-null
|
|
1478
|
+
* ```
|
|
1479
|
+
*/
|
|
1480
|
+
declare function findOneOrThrow<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, options?: FindOneOptions): Promise<InferDocument<TDef>>;
|
|
1481
|
+
/**
|
|
1482
|
+
* Options for {@link find}.
|
|
1483
|
+
*/
|
|
1484
|
+
type FindOptions = {
|
|
1485
|
+
/** Override the collection-level validation mode, or `false` to skip validation entirely. */
|
|
1486
|
+
validate?: ValidationMode | false;
|
|
1487
|
+
};
|
|
1488
|
+
/**
|
|
1489
|
+
* Find all documents matching the filter, returning a chainable typed cursor.
|
|
1490
|
+
*
|
|
1491
|
+
* The cursor is lazy — no query is executed until a terminal method
|
|
1492
|
+
* (`toArray`, `for await`) is called. Use `sort`, `skip`, and `limit`
|
|
1493
|
+
* to shape the query before executing.
|
|
1494
|
+
*
|
|
1495
|
+
* Each document is validated against the collection's Zod schema when
|
|
1496
|
+
* a terminal method consumes it.
|
|
1497
|
+
*
|
|
1498
|
+
* @param handle - The collection handle to query.
|
|
1499
|
+
* @param filter - Type-safe filter to match documents.
|
|
1500
|
+
* @param options - Optional validation overrides.
|
|
1501
|
+
* @returns A typed cursor for chaining query modifiers.
|
|
1502
|
+
*
|
|
1503
|
+
* @example
|
|
1504
|
+
* ```ts
|
|
1505
|
+
* const admins = await find(users, { role: 'admin' })
|
|
1506
|
+
* .sort({ name: 1 })
|
|
1507
|
+
* .limit(10)
|
|
1508
|
+
* .toArray()
|
|
1509
|
+
* ```
|
|
1510
|
+
*
|
|
1511
|
+
* @example
|
|
1512
|
+
* ```ts
|
|
1513
|
+
* for await (const user of find(users, {})) {
|
|
1514
|
+
* console.log(user.name)
|
|
1515
|
+
* }
|
|
1516
|
+
* ```
|
|
1517
|
+
*/
|
|
1518
|
+
declare function find<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, options?: FindOptions): TypedFindCursor<TDef, IndexNames<TDef>>;
|
|
1519
|
+
|
|
1520
|
+
/**
|
|
1521
|
+
* Extracts the element type from an array type.
|
|
1522
|
+
*
|
|
1523
|
+
* @example
|
|
1524
|
+
* ```ts
|
|
1525
|
+
* type E = ArrayElement<string[]> // string
|
|
1526
|
+
* type N = ArrayElement<number[]> // number
|
|
1527
|
+
* ```
|
|
1528
|
+
*/
|
|
1529
|
+
type ArrayElement<T> = T extends ReadonlyArray<infer E> ? E : never;
|
|
1530
|
+
/**
|
|
1531
|
+
* Fields valid for `$set`, `$setOnInsert`, `$min`, and `$max` operators.
|
|
1532
|
+
*
|
|
1533
|
+
* Allows top-level fields with matching value types plus dot-notation paths
|
|
1534
|
+
* for nested field updates.
|
|
1535
|
+
*
|
|
1536
|
+
* @example
|
|
1537
|
+
* ```ts
|
|
1538
|
+
* const set: SetFields<User> = { name: 'Alice', 'address.city': 'NYC' }
|
|
1539
|
+
* ```
|
|
1540
|
+
*/
|
|
1541
|
+
type SetFields<T> = {
|
|
1542
|
+
[K in keyof T]?: T[K];
|
|
1543
|
+
} & {
|
|
1544
|
+
[P in DotPaths<T>]?: DotPathType<T, P>;
|
|
1545
|
+
};
|
|
1546
|
+
/**
|
|
1547
|
+
* Fields valid for the `$inc` operator — only number-typed fields.
|
|
1548
|
+
*
|
|
1549
|
+
* Includes dot-notation paths that resolve to number types.
|
|
1550
|
+
*
|
|
1551
|
+
* @example
|
|
1552
|
+
* ```ts
|
|
1553
|
+
* const inc: IncFields<User> = { age: 1, 'stats.views': 5 }
|
|
1554
|
+
* ```
|
|
1555
|
+
*/
|
|
1556
|
+
type IncFields<T> = {
|
|
1557
|
+
[K in keyof T as NonNullable<T[K]> extends number ? K : never]?: number;
|
|
1558
|
+
} & {
|
|
1559
|
+
[P in DotPaths<T> as DotPathType<T, P> extends number ? P : never]?: number;
|
|
1560
|
+
};
|
|
1561
|
+
/**
|
|
1562
|
+
* Modifiers for the `$push` operator.
|
|
1563
|
+
*
|
|
1564
|
+
* Use with `$push` to insert multiple elements and control array position/size.
|
|
1565
|
+
*
|
|
1566
|
+
* @example
|
|
1567
|
+
* ```ts
|
|
1568
|
+
* const push = { tags: { $each: ['a', 'b'], $position: 0, $slice: 10 } }
|
|
1569
|
+
* ```
|
|
1570
|
+
*/
|
|
1571
|
+
type PushModifiers<E> = {
|
|
1572
|
+
/** Array of elements to push. */
|
|
1573
|
+
$each: E[];
|
|
1574
|
+
/** Position at which to insert elements. */
|
|
1575
|
+
$position?: number;
|
|
1576
|
+
/** Maximum array length after push. */
|
|
1577
|
+
$slice?: number;
|
|
1578
|
+
/** Sort order applied after push. */
|
|
1579
|
+
$sort?: 1 | -1 | Record<string, 1 | -1>;
|
|
1580
|
+
};
|
|
1581
|
+
/**
|
|
1582
|
+
* Fields valid for the `$push` operator — only array-typed fields.
|
|
1583
|
+
*
|
|
1584
|
+
* Accepts a single element value or a modifier object with `$each`.
|
|
1585
|
+
*
|
|
1586
|
+
* @example
|
|
1587
|
+
* ```ts
|
|
1588
|
+
* const push: PushFields<User> = { tags: 'dev' }
|
|
1589
|
+
* const pushMany: PushFields<User> = { tags: { $each: ['a', 'b'] } }
|
|
1590
|
+
* ```
|
|
1591
|
+
*/
|
|
1592
|
+
type PushFields<T> = {
|
|
1593
|
+
[K in keyof T as NonNullable<T[K]> extends ReadonlyArray<unknown> ? K : never]?: ArrayElement<NonNullable<T[K]>> | PushModifiers<ArrayElement<NonNullable<T[K]>>>;
|
|
1594
|
+
};
|
|
1595
|
+
/**
|
|
1596
|
+
* Fields valid for the `$pull` operator — only array-typed fields.
|
|
1597
|
+
*
|
|
1598
|
+
* For primitive arrays: accepts a value or comparison operators.
|
|
1599
|
+
* For object arrays: also accepts a `TypedFilter` on the element type.
|
|
1600
|
+
*
|
|
1601
|
+
* @example
|
|
1602
|
+
* ```ts
|
|
1603
|
+
* const pull: PullFields<User> = { tags: 'old' }
|
|
1604
|
+
* const pullQuery: PullFields<User> = { scores: { $lt: 50 } }
|
|
1605
|
+
* const pullObj: PullFields<User> = { comments: { author: 'spam' } }
|
|
1606
|
+
* ```
|
|
1607
|
+
*/
|
|
1608
|
+
type PullFields<T> = {
|
|
1609
|
+
[K in keyof T as NonNullable<T[K]> extends ReadonlyArray<unknown> ? K : never]?: ArrayElement<NonNullable<T[K]>> | ComparisonOperators<ArrayElement<NonNullable<T[K]>>> | (ArrayElement<NonNullable<T[K]>> extends Record<string, unknown> ? TypedFilter<ArrayElement<NonNullable<T[K]>>> : unknown);
|
|
1610
|
+
};
|
|
1611
|
+
/**
|
|
1612
|
+
* Modifier for the `$addToSet` operator's `$each` syntax.
|
|
1613
|
+
*
|
|
1614
|
+
* @example
|
|
1615
|
+
* ```ts
|
|
1616
|
+
* const addToSet = { tags: { $each: ['a', 'b'] } }
|
|
1617
|
+
* ```
|
|
1618
|
+
*/
|
|
1619
|
+
type AddToSetEach<E> = {
|
|
1620
|
+
$each: E[];
|
|
1621
|
+
};
|
|
1622
|
+
/**
|
|
1623
|
+
* Fields valid for the `$addToSet` operator — only array-typed fields.
|
|
1624
|
+
*
|
|
1625
|
+
* Accepts a single element value or `{ $each: [...] }` for multiple elements.
|
|
1626
|
+
*
|
|
1627
|
+
* @example
|
|
1628
|
+
* ```ts
|
|
1629
|
+
* const add: AddToSetFields<User> = { tags: 'dev' }
|
|
1630
|
+
* const addMany: AddToSetFields<User> = { tags: { $each: ['a', 'b'] } }
|
|
1631
|
+
* ```
|
|
1632
|
+
*/
|
|
1633
|
+
type AddToSetFields<T> = {
|
|
1634
|
+
[K in keyof T as NonNullable<T[K]> extends ReadonlyArray<unknown> ? K : never]?: ArrayElement<NonNullable<T[K]>> | AddToSetEach<ArrayElement<NonNullable<T[K]>>>;
|
|
1635
|
+
};
|
|
1636
|
+
/**
|
|
1637
|
+
* Fields valid for the `$pop` operator — only array-typed fields.
|
|
1638
|
+
*
|
|
1639
|
+
* Value `1` removes the last element, `-1` removes the first.
|
|
1640
|
+
*
|
|
1641
|
+
* @example
|
|
1642
|
+
* ```ts
|
|
1643
|
+
* const pop: PopFields<User> = { tags: -1 } // remove first
|
|
1644
|
+
* ```
|
|
1645
|
+
*/
|
|
1646
|
+
type PopFields<T> = {
|
|
1647
|
+
[K in keyof T as NonNullable<T[K]> extends ReadonlyArray<unknown> ? K : never]?: 1 | -1;
|
|
1648
|
+
};
|
|
1649
|
+
/**
|
|
1650
|
+
* Fields valid for the `$unset` operator — any existing field.
|
|
1651
|
+
*
|
|
1652
|
+
* Value is `''`, `true`, or `1` (all mean "remove this field").
|
|
1653
|
+
*
|
|
1654
|
+
* @example
|
|
1655
|
+
* ```ts
|
|
1656
|
+
* const unset: UnsetFields<User> = { middleName: '' }
|
|
1657
|
+
* ```
|
|
1658
|
+
*/
|
|
1659
|
+
type UnsetFields<T> = {
|
|
1660
|
+
[K in keyof T]?: '' | true | 1;
|
|
1661
|
+
};
|
|
1662
|
+
/**
|
|
1663
|
+
* Fields valid for the `$currentDate` operator — only Date-typed fields.
|
|
1664
|
+
*
|
|
1665
|
+
* Sets the field to the current date. Value is `true` or `{ $type: 'date' }`.
|
|
1666
|
+
*
|
|
1667
|
+
* @example
|
|
1668
|
+
* ```ts
|
|
1669
|
+
* const cd: CurrentDateFields<User> = { createdAt: true }
|
|
1670
|
+
* ```
|
|
1671
|
+
*/
|
|
1672
|
+
type CurrentDateFields<T> = {
|
|
1673
|
+
[K in keyof T as NonNullable<T[K]> extends Date ? K : never]?: true | {
|
|
1674
|
+
$type: 'date';
|
|
1675
|
+
};
|
|
1676
|
+
};
|
|
1677
|
+
/**
|
|
1678
|
+
* Fields valid for the `$rename` operator.
|
|
1679
|
+
*
|
|
1680
|
+
* Renames an existing field to a new name. Key is the current field name,
|
|
1681
|
+
* value is the new name as a string.
|
|
1682
|
+
*
|
|
1683
|
+
* @example
|
|
1684
|
+
* ```ts
|
|
1685
|
+
* const rename: RenameFields<User> = { name: 'fullName' }
|
|
1686
|
+
* ```
|
|
1687
|
+
*/
|
|
1688
|
+
type RenameFields<T> = {
|
|
1689
|
+
[K in keyof T & string]?: string;
|
|
1690
|
+
};
|
|
1691
|
+
/**
|
|
1692
|
+
* Strict type-safe MongoDB update filter.
|
|
1693
|
+
*
|
|
1694
|
+
* Validates update operators against field types at compile time. Each operator
|
|
1695
|
+
* constrains which fields it accepts (e.g. `$inc` only on numbers, `$push` only
|
|
1696
|
+
* on arrays). Supports dot-notation paths for nested field access.
|
|
1697
|
+
*
|
|
1698
|
+
* @example
|
|
1699
|
+
* ```ts
|
|
1700
|
+
* const update: TypedUpdateFilter<User> = {
|
|
1701
|
+
* $set: { name: 'Alice' },
|
|
1702
|
+
* $inc: { age: 1 },
|
|
1703
|
+
* }
|
|
1704
|
+
* ```
|
|
1705
|
+
*/
|
|
1706
|
+
type TypedUpdateFilter<T> = {
|
|
1707
|
+
/** Sets the value of one or more fields. */
|
|
1708
|
+
$set?: SetFields<T>;
|
|
1709
|
+
/** Sets fields only when inserting (upsert). Same typing as `$set`. */
|
|
1710
|
+
$setOnInsert?: SetFields<T>;
|
|
1711
|
+
/** Increments numeric fields by the given amount. Only accepts number-typed fields. */
|
|
1712
|
+
$inc?: IncFields<T>;
|
|
1713
|
+
/** Updates the field if the given value is less than the current value. */
|
|
1714
|
+
$min?: SetFields<T>;
|
|
1715
|
+
/** Updates the field if the given value is greater than the current value. */
|
|
1716
|
+
$max?: SetFields<T>;
|
|
1717
|
+
/** Appends a value to an array field. Supports `$each`, `$position`, `$slice`, `$sort`. */
|
|
1718
|
+
$push?: PushFields<T>;
|
|
1719
|
+
/** Removes matching values from an array field. */
|
|
1720
|
+
$pull?: PullFields<T>;
|
|
1721
|
+
/** Adds a value to an array only if it doesn't already exist. */
|
|
1722
|
+
$addToSet?: AddToSetFields<T>;
|
|
1723
|
+
/** Removes the first (`-1`) or last (`1`) element of an array. */
|
|
1724
|
+
$pop?: PopFields<T>;
|
|
1725
|
+
/** Removes the specified fields from the document. */
|
|
1726
|
+
$unset?: UnsetFields<T>;
|
|
1727
|
+
/** Sets the field to the current date. Only accepts Date-typed fields. */
|
|
1728
|
+
$currentDate?: CurrentDateFields<T>;
|
|
1729
|
+
/** Renames a field. */
|
|
1730
|
+
$rename?: RenameFields<T>;
|
|
1731
|
+
};
|
|
1732
|
+
|
|
1733
|
+
/**
|
|
1734
|
+
* Options for {@link updateOne} and {@link updateMany}.
|
|
1735
|
+
*/
|
|
1736
|
+
type UpdateOptions = {
|
|
1737
|
+
/** When `true`, inserts a new document if no document matches the filter. */
|
|
1738
|
+
upsert?: boolean;
|
|
1739
|
+
};
|
|
1740
|
+
/**
|
|
1741
|
+
* Options for {@link findOneAndUpdate}.
|
|
1742
|
+
*/
|
|
1743
|
+
type FindOneAndUpdateOptions = {
|
|
1744
|
+
/** Whether to return the document before or after the update. Defaults to `'after'`. */
|
|
1745
|
+
returnDocument?: 'before' | 'after';
|
|
1746
|
+
/** When `true`, inserts a new document if no document matches the filter. */
|
|
1747
|
+
upsert?: boolean;
|
|
1748
|
+
/** Override the collection-level validation mode, or `false` to skip validation entirely. */
|
|
1749
|
+
validate?: ValidationMode | false;
|
|
1750
|
+
};
|
|
1751
|
+
/**
|
|
1752
|
+
* Update a single document matching the filter.
|
|
1753
|
+
*
|
|
1754
|
+
* Applies the update operators to the first document that matches the filter.
|
|
1755
|
+
* Does not validate the update against the Zod schema — validation happens
|
|
1756
|
+
* at the field-operator level through {@link TypedUpdateFilter}.
|
|
1757
|
+
*
|
|
1758
|
+
* @param handle - The collection handle to update in.
|
|
1759
|
+
* @param filter - Type-safe filter to match documents.
|
|
1760
|
+
* @param update - Type-safe update operators to apply.
|
|
1761
|
+
* @param options - Optional settings such as `upsert`.
|
|
1762
|
+
* @returns The MongoDB `UpdateResult` with match/modify counts.
|
|
1763
|
+
*
|
|
1764
|
+
* @example
|
|
1765
|
+
* ```ts
|
|
1766
|
+
* const result = await updateOne(users, { name: 'Ada' }, { $set: { role: 'admin' } })
|
|
1767
|
+
* console.log(result.modifiedCount) // 1
|
|
1768
|
+
* ```
|
|
1769
|
+
*/
|
|
1770
|
+
declare function updateOne<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, update: TypedUpdateFilter<InferDocument<TDef>>, options?: UpdateOptions): Promise<UpdateResult>;
|
|
1771
|
+
/**
|
|
1772
|
+
* Update all documents matching the filter.
|
|
1773
|
+
*
|
|
1774
|
+
* Applies the update operators to every document that matches the filter.
|
|
1775
|
+
* Does not validate the update against the Zod schema — validation happens
|
|
1776
|
+
* at the field-operator level through {@link TypedUpdateFilter}.
|
|
1777
|
+
*
|
|
1778
|
+
* @param handle - The collection handle to update in.
|
|
1779
|
+
* @param filter - Type-safe filter to match documents.
|
|
1780
|
+
* @param update - Type-safe update operators to apply.
|
|
1781
|
+
* @param options - Optional settings such as `upsert`.
|
|
1782
|
+
* @returns The MongoDB `UpdateResult` with match/modify counts.
|
|
1783
|
+
*
|
|
1784
|
+
* @example
|
|
1785
|
+
* ```ts
|
|
1786
|
+
* const result = await updateMany(users, { role: 'guest' }, { $set: { role: 'user' } })
|
|
1787
|
+
* console.log(result.modifiedCount) // number of guests promoted
|
|
1788
|
+
* ```
|
|
1789
|
+
*/
|
|
1790
|
+
declare function updateMany<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, update: TypedUpdateFilter<InferDocument<TDef>>, options?: UpdateOptions): Promise<UpdateResult>;
|
|
1791
|
+
/**
|
|
1792
|
+
* Find a single document matching the filter, apply an update, and return the document.
|
|
1793
|
+
*
|
|
1794
|
+
* By default, returns the document **after** the update is applied. Set
|
|
1795
|
+
* `returnDocument: 'before'` to get the pre-update snapshot. The returned
|
|
1796
|
+
* document is validated against the collection's Zod schema using the same
|
|
1797
|
+
* resolution logic as {@link findOne}.
|
|
1798
|
+
*
|
|
1799
|
+
* @param handle - The collection handle to update in.
|
|
1800
|
+
* @param filter - Type-safe filter to match documents.
|
|
1801
|
+
* @param update - Type-safe update operators to apply.
|
|
1802
|
+
* @param options - Optional settings: `returnDocument`, `upsert`, `validate`.
|
|
1803
|
+
* @returns The matched document (before or after update), or `null` if no document matches.
|
|
1804
|
+
* @throws {ZodmonValidationError} When the returned document fails schema validation in strict mode.
|
|
1805
|
+
*
|
|
1806
|
+
* @example
|
|
1807
|
+
* ```ts
|
|
1808
|
+
* const user = await findOneAndUpdate(
|
|
1809
|
+
* users,
|
|
1810
|
+
* { name: 'Ada' },
|
|
1811
|
+
* { $set: { role: 'admin' } },
|
|
1812
|
+
* )
|
|
1813
|
+
* if (user) console.log(user.role) // 'admin' (returned after update)
|
|
1814
|
+
* ```
|
|
1815
|
+
*
|
|
1816
|
+
* @example
|
|
1817
|
+
* ```ts
|
|
1818
|
+
* const before = await findOneAndUpdate(
|
|
1819
|
+
* users,
|
|
1820
|
+
* { name: 'Ada' },
|
|
1821
|
+
* { $inc: { loginCount: 1 } },
|
|
1822
|
+
* { returnDocument: 'before' },
|
|
1823
|
+
* )
|
|
1824
|
+
* ```
|
|
1825
|
+
*/
|
|
1826
|
+
declare function findOneAndUpdate<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, update: TypedUpdateFilter<InferDocument<TDef>>, options?: FindOneAndUpdateOptions): Promise<InferDocument<TDef> | null>;
|
|
1827
|
+
|
|
1828
|
+
/**
|
|
1829
|
+
* Options controlling how {@link syncIndexes} behaves.
|
|
1830
|
+
*
|
|
1831
|
+
* @example
|
|
1832
|
+
* ```ts
|
|
1833
|
+
* await users.syncIndexes({ dryRun: true })
|
|
1834
|
+
* await users.syncIndexes({ dropOrphaned: true })
|
|
1835
|
+
* ```
|
|
1836
|
+
*/
|
|
1837
|
+
type SyncIndexesOptions = {
|
|
1838
|
+
/**
|
|
1839
|
+
* When `true`, compute the diff without actually creating, dropping, or
|
|
1840
|
+
* modifying any indexes. The returned {@link SyncIndexesResult} shows what
|
|
1841
|
+
* *would* happen.
|
|
1842
|
+
*/
|
|
1843
|
+
dryRun?: boolean;
|
|
1844
|
+
/**
|
|
1845
|
+
* When `true`, drop indexes that exist in MongoDB but are not declared in
|
|
1846
|
+
* the schema. Also drops and recreates stale indexes (same key, different
|
|
1847
|
+
* options). When `false` (the default), orphaned and stale indexes are
|
|
1848
|
+
* reported but left untouched.
|
|
1849
|
+
*/
|
|
1850
|
+
dropOrphaned?: boolean;
|
|
1851
|
+
};
|
|
1852
|
+
/**
|
|
1853
|
+
* Describes an index whose key matches a desired index but whose options differ.
|
|
1854
|
+
*
|
|
1855
|
+
* Returned in {@link SyncIndexesResult.stale} so the caller can decide whether
|
|
1856
|
+
* to manually reconcile or re-run with `dropOrphaned: true`.
|
|
1857
|
+
*
|
|
1858
|
+
* @example
|
|
1859
|
+
* ```ts
|
|
1860
|
+
* const result = await users.syncIndexes()
|
|
1861
|
+
* for (const s of result.stale) {
|
|
1862
|
+
* console.log(`${s.name}: key=${JSON.stringify(s.key)}`)
|
|
1863
|
+
* console.log(` existing=${JSON.stringify(s.existing)}`)
|
|
1864
|
+
* console.log(` desired=${JSON.stringify(s.desired)}`)
|
|
1865
|
+
* }
|
|
1866
|
+
* ```
|
|
1867
|
+
*/
|
|
1868
|
+
type StaleIndex = {
|
|
1869
|
+
/** The MongoDB index name (e.g. `'email_1'`). */
|
|
1870
|
+
name: string;
|
|
1871
|
+
/** The index key spec (e.g. `{ email: 1 }`). */
|
|
1872
|
+
key: Record<string, 1 | -1 | 'text'>;
|
|
1873
|
+
/** The relevant options currently set on the existing index. */
|
|
1874
|
+
existing: Record<string, unknown>;
|
|
1875
|
+
/** The options the schema declares for this index. */
|
|
1876
|
+
desired: Record<string, unknown>;
|
|
1877
|
+
};
|
|
1878
|
+
/**
|
|
1879
|
+
* The result of a {@link syncIndexes} call.
|
|
1880
|
+
*
|
|
1881
|
+
* Every array contains index names. `stale` contains full details so the
|
|
1882
|
+
* caller can inspect the mismatch.
|
|
1883
|
+
*
|
|
1884
|
+
* @example
|
|
1885
|
+
* ```ts
|
|
1886
|
+
* const result = await users.syncIndexes()
|
|
1887
|
+
* console.log('created:', result.created)
|
|
1888
|
+
* console.log('dropped:', result.dropped)
|
|
1889
|
+
* console.log('skipped:', result.skipped)
|
|
1890
|
+
* console.log('stale:', result.stale.map(s => s.name))
|
|
1891
|
+
* ```
|
|
1892
|
+
*/
|
|
1893
|
+
type SyncIndexesResult = {
|
|
1894
|
+
/** Names of indexes that were created (or would be created in dryRun mode). */
|
|
1895
|
+
created: string[];
|
|
1896
|
+
/** Names of indexes that were dropped (or would be dropped in dryRun mode). */
|
|
1897
|
+
dropped: string[];
|
|
1898
|
+
/** Names of indexes that already existed with matching options — no action taken. */
|
|
1899
|
+
skipped: string[];
|
|
1900
|
+
/** Indexes whose key matches a desired spec but whose options differ. */
|
|
1901
|
+
stale: StaleIndex[];
|
|
1902
|
+
};
|
|
1903
|
+
|
|
1904
|
+
/**
|
|
1905
|
+
* Typed wrapper around a MongoDB driver `Collection`.
|
|
1906
|
+
*
|
|
1907
|
+
* Created by {@link Database.use}. Holds the original `CollectionDefinition`
|
|
1908
|
+
* (for runtime schema validation and index metadata) alongside the native
|
|
1909
|
+
* driver collection parameterized with the inferred document type.
|
|
1910
|
+
*
|
|
1911
|
+
* @typeParam TDef - The collection definition type. Used to derive both
|
|
1912
|
+
* the document type (`InferDocument`) and the insert type (`InferInsert`).
|
|
1913
|
+
*/
|
|
1914
|
+
declare class CollectionHandle<TDef extends AnyCollection = AnyCollection> {
|
|
1915
|
+
/** The collection definition containing schema, name, and index metadata. */
|
|
1916
|
+
readonly definition: TDef;
|
|
1917
|
+
/** The underlying MongoDB driver collection, typed to the inferred document type. */
|
|
1918
|
+
readonly native: Collection<InferDocument<TDef>>;
|
|
1919
|
+
constructor(definition: TDef, native: Collection<InferDocument<TDef>>);
|
|
1920
|
+
/**
|
|
1921
|
+
* Insert a single document into the collection.
|
|
1922
|
+
*
|
|
1923
|
+
* Validates the input against the collection's Zod schema before writing.
|
|
1924
|
+
* Schema defaults (including auto-generated `_id`) are applied during
|
|
1925
|
+
* validation. Returns the full document with all defaults filled in.
|
|
1926
|
+
*
|
|
1927
|
+
* @param doc - The document to insert. Fields with `.default()` are optional.
|
|
1928
|
+
* @returns The inserted document with `_id` and all defaults applied.
|
|
1929
|
+
* @throws {ZodmonValidationError} When the document fails schema validation.
|
|
1930
|
+
*
|
|
1931
|
+
* @example
|
|
1932
|
+
* ```ts
|
|
1933
|
+
* const users = db.use(Users)
|
|
1934
|
+
* const user = await users.insertOne({ name: 'Ada' })
|
|
1935
|
+
* console.log(user._id) // ObjectId (auto-generated)
|
|
1936
|
+
* console.log(user.role) // 'user' (schema default)
|
|
1937
|
+
* ```
|
|
1938
|
+
*/
|
|
1939
|
+
insertOne(doc: InferInsert<TDef>): Promise<InferDocument<TDef>>;
|
|
1940
|
+
/**
|
|
1941
|
+
* Insert multiple documents into the collection.
|
|
1942
|
+
*
|
|
1943
|
+
* Validates every document against the collection's Zod schema before
|
|
1944
|
+
* writing any to MongoDB. If any document fails validation, none are
|
|
1945
|
+
* inserted (fail-fast before the driver call).
|
|
1946
|
+
*
|
|
1947
|
+
* @param docs - The documents to insert.
|
|
1948
|
+
* @returns The inserted documents with `_id` and all defaults applied.
|
|
1949
|
+
* @throws {ZodmonValidationError} When any document fails schema validation.
|
|
1950
|
+
*
|
|
1951
|
+
* @example
|
|
1952
|
+
* ```ts
|
|
1953
|
+
* const created = await users.insertMany([
|
|
1954
|
+
* { name: 'Ada' },
|
|
1955
|
+
* { name: 'Bob', role: 'admin' },
|
|
1956
|
+
* ])
|
|
1957
|
+
* ```
|
|
1958
|
+
*/
|
|
1959
|
+
insertMany(docs: InferInsert<TDef>[]): Promise<InferDocument<TDef>[]>;
|
|
1960
|
+
/**
|
|
1961
|
+
* Find a single document matching the filter.
|
|
1962
|
+
*
|
|
1963
|
+
* Queries MongoDB, then validates the fetched document against the collection's
|
|
1964
|
+
* Zod schema. Validation mode is resolved from the per-query option, falling
|
|
1965
|
+
* back to the collection-level default (which defaults to `'strict'`).
|
|
1966
|
+
*
|
|
1967
|
+
* @param filter - Type-safe filter to match documents.
|
|
1968
|
+
* @param options - Optional projection and validation overrides.
|
|
1969
|
+
* @returns The matched document, or `null` if no document matches.
|
|
1970
|
+
* @throws {ZodmonValidationError} When the fetched document fails schema validation in strict mode.
|
|
1971
|
+
*
|
|
1972
|
+
* @example
|
|
1973
|
+
* ```ts
|
|
1974
|
+
* const users = db.use(Users)
|
|
1975
|
+
* const user = await users.findOne({ name: 'Ada' })
|
|
1976
|
+
* if (user) console.log(user.role)
|
|
1977
|
+
* ```
|
|
1978
|
+
*/
|
|
1979
|
+
findOne(filter: TypedFilter<InferDocument<TDef>>, options?: FindOneOptions): Promise<InferDocument<TDef> | null>;
|
|
1980
|
+
/**
|
|
1981
|
+
* Find a single document matching the filter, or throw if none exists.
|
|
1982
|
+
*
|
|
1983
|
+
* Behaves identically to {@link findOne} but throws {@link ZodmonNotFoundError}
|
|
1984
|
+
* instead of returning `null` when no document matches the filter.
|
|
1985
|
+
*
|
|
1986
|
+
* @param filter - Type-safe filter to match documents.
|
|
1987
|
+
* @param options - Optional projection and validation overrides.
|
|
1988
|
+
* @returns The matched document (never null).
|
|
1989
|
+
* @throws {ZodmonNotFoundError} When no document matches the filter.
|
|
1990
|
+
* @throws {ZodmonValidationError} When the fetched document fails schema validation in strict mode.
|
|
1991
|
+
*
|
|
1992
|
+
* @example
|
|
1993
|
+
* ```ts
|
|
1994
|
+
* const users = db.use(Users)
|
|
1995
|
+
* const user = await users.findOneOrThrow({ name: 'Ada' })
|
|
1996
|
+
* console.log(user.role) // guaranteed non-null
|
|
1997
|
+
* ```
|
|
1998
|
+
*/
|
|
1999
|
+
findOneOrThrow(filter: TypedFilter<InferDocument<TDef>>, options?: FindOneOptions): Promise<InferDocument<TDef>>;
|
|
2000
|
+
/**
|
|
2001
|
+
* Find all documents matching the filter, returning a chainable typed cursor.
|
|
2002
|
+
*
|
|
2003
|
+
* The cursor is lazy — no query is executed until a terminal method
|
|
2004
|
+
* (`toArray`, `for await`) is called. Use `sort`, `skip`, and `limit`
|
|
2005
|
+
* to shape the query before executing.
|
|
2006
|
+
*
|
|
2007
|
+
* @param filter - Type-safe filter to match documents.
|
|
2008
|
+
* @param options - Optional validation overrides.
|
|
2009
|
+
* @returns A typed cursor for chaining query modifiers.
|
|
2010
|
+
*
|
|
2011
|
+
* @example
|
|
2012
|
+
* ```ts
|
|
2013
|
+
* const users = db.use(Users)
|
|
2014
|
+
* const admins = await users.find({ role: 'admin' })
|
|
2015
|
+
* .sort({ name: 1 })
|
|
2016
|
+
* .limit(10)
|
|
2017
|
+
* .toArray()
|
|
2018
|
+
* ```
|
|
2019
|
+
*/
|
|
2020
|
+
find(filter: TypedFilter<InferDocument<TDef>>, options?: FindOptions): TypedFindCursor<TDef, IndexNames<TDef>>;
|
|
2021
|
+
/**
|
|
2022
|
+
* Update a single document matching the filter.
|
|
2023
|
+
*
|
|
2024
|
+
* Applies the update operators to the first document that matches the filter.
|
|
2025
|
+
* Does not validate the update against the Zod schema — validation happens
|
|
2026
|
+
* at the field-operator level through {@link TypedUpdateFilter}.
|
|
2027
|
+
*
|
|
2028
|
+
* @param filter - Type-safe filter to match documents.
|
|
2029
|
+
* @param update - Type-safe update operators to apply.
|
|
2030
|
+
* @param options - Optional settings such as `upsert`.
|
|
2031
|
+
* @returns The MongoDB `UpdateResult` with match/modify counts.
|
|
2032
|
+
*
|
|
2033
|
+
* @example
|
|
2034
|
+
* ```ts
|
|
2035
|
+
* const users = db.use(Users)
|
|
2036
|
+
* const result = await users.updateOne({ name: 'Ada' }, { $set: { role: 'admin' } })
|
|
2037
|
+
* console.log(result.modifiedCount) // 1
|
|
2038
|
+
* ```
|
|
2039
|
+
*/
|
|
2040
|
+
updateOne(filter: TypedFilter<InferDocument<TDef>>, update: TypedUpdateFilter<InferDocument<TDef>>, options?: UpdateOptions): Promise<UpdateResult>;
|
|
2041
|
+
/**
|
|
2042
|
+
* Update all documents matching the filter.
|
|
2043
|
+
*
|
|
2044
|
+
* Applies the update operators to every document that matches the filter.
|
|
2045
|
+
* Does not validate the update against the Zod schema — validation happens
|
|
2046
|
+
* at the field-operator level through {@link TypedUpdateFilter}.
|
|
2047
|
+
*
|
|
2048
|
+
* @param filter - Type-safe filter to match documents.
|
|
2049
|
+
* @param update - Type-safe update operators to apply.
|
|
2050
|
+
* @param options - Optional settings such as `upsert`.
|
|
2051
|
+
* @returns The MongoDB `UpdateResult` with match/modify counts.
|
|
2052
|
+
*
|
|
2053
|
+
* @example
|
|
2054
|
+
* ```ts
|
|
2055
|
+
* const users = db.use(Users)
|
|
2056
|
+
* const result = await users.updateMany({ role: 'guest' }, { $set: { role: 'user' } })
|
|
2057
|
+
* console.log(result.modifiedCount) // number of guests promoted
|
|
2058
|
+
* ```
|
|
2059
|
+
*/
|
|
2060
|
+
updateMany(filter: TypedFilter<InferDocument<TDef>>, update: TypedUpdateFilter<InferDocument<TDef>>, options?: UpdateOptions): Promise<UpdateResult>;
|
|
2061
|
+
/**
|
|
2062
|
+
* Find a single document matching the filter, apply an update, and return the document.
|
|
2063
|
+
*
|
|
2064
|
+
* By default, returns the document **after** the update is applied. Set
|
|
2065
|
+
* `returnDocument: 'before'` to get the pre-update snapshot. The returned
|
|
2066
|
+
* document is validated against the collection's Zod schema using the same
|
|
2067
|
+
* resolution logic as {@link findOne}.
|
|
2068
|
+
*
|
|
2069
|
+
* @param filter - Type-safe filter to match documents.
|
|
2070
|
+
* @param update - Type-safe update operators to apply.
|
|
2071
|
+
* @param options - Optional settings: `returnDocument`, `upsert`, `validate`.
|
|
2072
|
+
* @returns The matched document (before or after update), or `null` if no document matches.
|
|
2073
|
+
* @throws {ZodmonValidationError} When the returned document fails schema validation in strict mode.
|
|
2074
|
+
*
|
|
2075
|
+
* @example
|
|
2076
|
+
* ```ts
|
|
2077
|
+
* const users = db.use(Users)
|
|
2078
|
+
* const user = await users.findOneAndUpdate(
|
|
2079
|
+
* { name: 'Ada' },
|
|
2080
|
+
* { $set: { role: 'admin' } },
|
|
2081
|
+
* )
|
|
2082
|
+
* if (user) console.log(user.role) // 'admin' (returned after update)
|
|
2083
|
+
* ```
|
|
2084
|
+
*/
|
|
2085
|
+
findOneAndUpdate(filter: TypedFilter<InferDocument<TDef>>, update: TypedUpdateFilter<InferDocument<TDef>>, options?: FindOneAndUpdateOptions): Promise<InferDocument<TDef> | null>;
|
|
2086
|
+
/**
|
|
2087
|
+
* Delete a single document matching the filter.
|
|
2088
|
+
*
|
|
2089
|
+
* Removes the first document that matches the filter from the collection.
|
|
2090
|
+
* No validation is performed — the document is deleted directly through
|
|
2091
|
+
* the MongoDB driver.
|
|
2092
|
+
*
|
|
2093
|
+
* @param filter - Type-safe filter to match documents.
|
|
2094
|
+
* @returns The MongoDB `DeleteResult` with the deleted count.
|
|
2095
|
+
*
|
|
2096
|
+
* @example
|
|
2097
|
+
* ```ts
|
|
2098
|
+
* const users = db.use(Users)
|
|
2099
|
+
* const result = await users.deleteOne({ name: 'Ada' })
|
|
2100
|
+
* console.log(result.deletedCount) // 1
|
|
2101
|
+
* ```
|
|
2102
|
+
*/
|
|
2103
|
+
deleteOne(filter: TypedFilter<InferDocument<TDef>>): Promise<DeleteResult>;
|
|
2104
|
+
/**
|
|
2105
|
+
* Delete all documents matching the filter.
|
|
2106
|
+
*
|
|
2107
|
+
* Removes every document that matches the filter from the collection.
|
|
2108
|
+
* No validation is performed — documents are deleted directly through
|
|
2109
|
+
* the MongoDB driver.
|
|
2110
|
+
*
|
|
2111
|
+
* @param filter - Type-safe filter to match documents.
|
|
2112
|
+
* @returns The MongoDB `DeleteResult` with the deleted count.
|
|
2113
|
+
*
|
|
2114
|
+
* @example
|
|
2115
|
+
* ```ts
|
|
2116
|
+
* const users = db.use(Users)
|
|
2117
|
+
* const result = await users.deleteMany({ role: 'guest' })
|
|
2118
|
+
* console.log(result.deletedCount) // number of guests removed
|
|
2119
|
+
* ```
|
|
2120
|
+
*/
|
|
2121
|
+
deleteMany(filter: TypedFilter<InferDocument<TDef>>): Promise<DeleteResult>;
|
|
2122
|
+
/**
|
|
2123
|
+
* Find a single document matching the filter, delete it, and return the document.
|
|
2124
|
+
*
|
|
2125
|
+
* Returns the deleted document, or `null` if no document matches the filter.
|
|
2126
|
+
* The returned document is validated against the collection's Zod schema
|
|
2127
|
+
* using the same resolution logic as {@link findOne}.
|
|
2128
|
+
*
|
|
2129
|
+
* @param filter - Type-safe filter to match documents.
|
|
2130
|
+
* @param options - Optional settings: `validate`.
|
|
2131
|
+
* @returns The deleted document, or `null` if no document matches.
|
|
2132
|
+
* @throws {ZodmonValidationError} When the returned document fails schema validation in strict mode.
|
|
2133
|
+
*
|
|
2134
|
+
* @example
|
|
2135
|
+
* ```ts
|
|
2136
|
+
* const users = db.use(Users)
|
|
2137
|
+
* const user = await users.findOneAndDelete({ name: 'Ada' })
|
|
2138
|
+
* if (user) console.log(user.name) // 'Ada' (the deleted document)
|
|
2139
|
+
* ```
|
|
2140
|
+
*/
|
|
2141
|
+
findOneAndDelete(filter: TypedFilter<InferDocument<TDef>>, options?: FindOneAndDeleteOptions): Promise<InferDocument<TDef> | null>;
|
|
2142
|
+
/**
|
|
2143
|
+
* Synchronize the indexes declared in this collection's schema with MongoDB.
|
|
2144
|
+
*
|
|
2145
|
+
* Compares the desired indexes (from field-level `.index()` / `.unique()` /
|
|
2146
|
+
* `.text()` / `.expireAfter()` and compound `indexes` in collection options)
|
|
2147
|
+
* with the indexes that currently exist in MongoDB, then creates, drops, or
|
|
2148
|
+
* reports differences depending on the options.
|
|
2149
|
+
*
|
|
2150
|
+
* @param options - Optional sync behavior (dryRun, dropOrphaned).
|
|
2151
|
+
* @returns A summary of created, dropped, skipped, and stale indexes.
|
|
2152
|
+
*
|
|
2153
|
+
* @example
|
|
2154
|
+
* ```ts
|
|
2155
|
+
* const users = db.use(Users)
|
|
2156
|
+
* const result = await users.syncIndexes()
|
|
2157
|
+
* console.log('Created:', result.created)
|
|
2158
|
+
* console.log('Stale:', result.stale.map(s => s.name))
|
|
2159
|
+
* ```
|
|
2160
|
+
*
|
|
2161
|
+
* @example
|
|
2162
|
+
* ```ts
|
|
2163
|
+
* // Dry run to preview changes without modifying the database
|
|
2164
|
+
* const diff = await users.syncIndexes({ dryRun: true })
|
|
2165
|
+
* console.log('Would create:', diff.created)
|
|
2166
|
+
* console.log('Would drop:', diff.dropped)
|
|
2167
|
+
* ```
|
|
2168
|
+
*/
|
|
2169
|
+
syncIndexes(options?: SyncIndexesOptions): Promise<SyncIndexesResult>;
|
|
2170
|
+
/**
|
|
2171
|
+
* Start a type-safe aggregation pipeline on this collection.
|
|
2172
|
+
*
|
|
2173
|
+
* Returns a fluent pipeline builder that tracks the output document
|
|
2174
|
+
* shape through each stage. The pipeline is lazy — no query executes
|
|
2175
|
+
* until a terminal method (`toArray`, `for await`, `explain`) is called.
|
|
2176
|
+
*
|
|
2177
|
+
* @returns A new pipeline builder starting with this collection's document type.
|
|
2178
|
+
*
|
|
2179
|
+
* @example
|
|
2180
|
+
* ```ts
|
|
2181
|
+
* const users = db.use(Users)
|
|
2182
|
+
* const result = await users.aggregate()
|
|
2183
|
+
* .match({ role: 'admin' })
|
|
2184
|
+
* .groupBy('role', { count: $count() })
|
|
2185
|
+
* .toArray()
|
|
2186
|
+
* ```
|
|
2187
|
+
*/
|
|
2188
|
+
aggregate(): AggregatePipeline<TDef, InferDocument<TDef>>;
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
/**
|
|
2192
|
+
* Immutable aggregation pipeline builder for type-safe MongoDB aggregations.
|
|
2193
|
+
*
|
|
2194
|
+
* Each stage method returns a **new** `AggregatePipeline` instance — the
|
|
2195
|
+
* original is never mutated. This makes it safe to branch from a shared base
|
|
2196
|
+
* pipeline without cross-contamination.
|
|
2197
|
+
*
|
|
2198
|
+
* Use {@link aggregate} to create a pipeline from a {@link CollectionHandle},
|
|
2199
|
+
* or call `raw()` to append arbitrary stages.
|
|
2200
|
+
*
|
|
2201
|
+
* @typeParam TDef - The collection definition type, used to derive document types.
|
|
2202
|
+
* @typeParam TOutput - The current output document type (changes as stages transform the shape).
|
|
2203
|
+
*
|
|
2204
|
+
* @example
|
|
2205
|
+
* ```ts
|
|
2206
|
+
* const results = await aggregate(users)
|
|
2207
|
+
* .raw({ $match: { role: 'admin' } })
|
|
2208
|
+
* .raw({ $sort: { name: 1 } })
|
|
2209
|
+
* .toArray()
|
|
2210
|
+
* ```
|
|
2211
|
+
*/
|
|
2212
|
+
declare class AggregatePipeline<TDef extends AnyCollection, TOutput> {
|
|
2213
|
+
protected readonly definition: TDef;
|
|
2214
|
+
private readonly nativeCollection;
|
|
2215
|
+
private readonly stages;
|
|
2216
|
+
constructor(definition: TDef, nativeCollection: Collection<InferDocument<TDef>>, stages: Document[]);
|
|
2217
|
+
/**
|
|
2218
|
+
* Append an arbitrary aggregation stage to the pipeline (escape hatch).
|
|
2219
|
+
*
|
|
2220
|
+
* Returns a new pipeline instance with the stage appended — the
|
|
2221
|
+
* original pipeline is not modified.
|
|
2222
|
+
*
|
|
2223
|
+
* Optionally accepts a type parameter `TNew` to change the output
|
|
2224
|
+
* type when the stage transforms the document shape.
|
|
2225
|
+
*
|
|
2226
|
+
* @typeParam TNew - The output type after this stage. Defaults to the current output type.
|
|
2227
|
+
* @param stage - A raw MongoDB aggregation stage document (e.g. `{ $match: { ... } }`).
|
|
2228
|
+
* @returns A new pipeline with the stage appended.
|
|
2229
|
+
*
|
|
2230
|
+
* @example
|
|
2231
|
+
* ```ts
|
|
2232
|
+
* const admins = aggregate(users)
|
|
2233
|
+
* .raw({ $match: { role: 'admin' } })
|
|
2234
|
+
* .toArray()
|
|
2235
|
+
* ```
|
|
2236
|
+
*
|
|
2237
|
+
* @example
|
|
2238
|
+
* ```ts
|
|
2239
|
+
* // Change output type with a $project stage
|
|
2240
|
+
* const names = aggregate(users)
|
|
2241
|
+
* .raw<{ name: string }>({ $project: { name: 1, _id: 0 } })
|
|
2242
|
+
* .toArray()
|
|
2243
|
+
* ```
|
|
2244
|
+
*/
|
|
2245
|
+
raw<TNew = TOutput>(stage: Document): AggregatePipeline<TDef, TNew>;
|
|
2246
|
+
/**
|
|
2247
|
+
* Execute the pipeline and return all results as an array.
|
|
2248
|
+
*
|
|
2249
|
+
* @returns A promise resolving to the array of output documents.
|
|
2250
|
+
*
|
|
2251
|
+
* @example
|
|
2252
|
+
* ```ts
|
|
2253
|
+
* const results = await aggregate(users)
|
|
2254
|
+
* .raw({ $match: { age: { $gte: 18 } } })
|
|
2255
|
+
* .toArray()
|
|
2256
|
+
* ```
|
|
2257
|
+
*/
|
|
2258
|
+
toArray(): Promise<TOutput[]>;
|
|
2259
|
+
/**
|
|
2260
|
+
* Stream pipeline results one document at a time via `for await...of`.
|
|
2261
|
+
*
|
|
2262
|
+
* @returns An async generator yielding output documents.
|
|
2263
|
+
*
|
|
2264
|
+
* @example
|
|
2265
|
+
* ```ts
|
|
2266
|
+
* for await (const user of aggregate(users).raw({ $match: { role: 'admin' } })) {
|
|
2267
|
+
* console.log(user.name)
|
|
2268
|
+
* }
|
|
2269
|
+
* ```
|
|
2270
|
+
*/
|
|
2271
|
+
[Symbol.asyncIterator](): AsyncGenerator<TOutput>;
|
|
2272
|
+
/**
|
|
2273
|
+
* Return the query execution plan without running the pipeline.
|
|
2274
|
+
*
|
|
2275
|
+
* Useful for debugging and understanding how MongoDB will process
|
|
2276
|
+
* the pipeline stages.
|
|
2277
|
+
*
|
|
2278
|
+
* @returns A promise resolving to the explain output document.
|
|
2279
|
+
*
|
|
2280
|
+
* @example
|
|
2281
|
+
* ```ts
|
|
2282
|
+
* const plan = await aggregate(users)
|
|
2283
|
+
* .raw({ $match: { role: 'admin' } })
|
|
2284
|
+
* .explain()
|
|
2285
|
+
* console.log(plan)
|
|
2286
|
+
* ```
|
|
2287
|
+
*/
|
|
2288
|
+
explain(): Promise<Document>;
|
|
2289
|
+
/**
|
|
2290
|
+
* Filter documents using a type-safe match expression.
|
|
2291
|
+
*
|
|
2292
|
+
* Appends a `$match` stage to the pipeline. The filter is constrained
|
|
2293
|
+
* to the current output type, so only valid fields and operators are accepted.
|
|
2294
|
+
*
|
|
2295
|
+
* Supports two forms of type narrowing:
|
|
2296
|
+
*
|
|
2297
|
+
* **Tier 1 — Explicit type parameter:**
|
|
2298
|
+
* ```ts
|
|
2299
|
+
* .match<{ role: 'engineer' | 'designer' }>({ role: { $in: ['engineer', 'designer'] } })
|
|
2300
|
+
* // role narrows to 'engineer' | 'designer'
|
|
2301
|
+
* ```
|
|
2302
|
+
*
|
|
2303
|
+
* **Tier 2 — Automatic inference from filter literals:**
|
|
2304
|
+
* ```ts
|
|
2305
|
+
* .match({ role: 'engineer' }) // role narrows to 'engineer'
|
|
2306
|
+
* .match({ role: { $ne: 'intern' } }) // role narrows to Exclude<Role, 'intern'>
|
|
2307
|
+
* .match({ role: { $in: ['engineer', 'designer'] as const } }) // needs as const
|
|
2308
|
+
* ```
|
|
2309
|
+
*
|
|
2310
|
+
* When no type parameter is provided and the filter doesn't contain
|
|
2311
|
+
* inferrable literals, the output type is unchanged (backward compatible).
|
|
2312
|
+
*
|
|
2313
|
+
* @typeParam TNarrow - Optional object mapping field names to narrowed types. Must be a subtype of the corresponding fields in TOutput.
|
|
2314
|
+
* @typeParam F - Inferred from the filter argument. Do not provide explicitly.
|
|
2315
|
+
* @param filter - A type-safe filter for the current output type.
|
|
2316
|
+
* @returns A new pipeline with the `$match` stage appended and output type narrowed.
|
|
2317
|
+
*
|
|
2318
|
+
* @example
|
|
2319
|
+
* ```ts
|
|
2320
|
+
* // Explicit narrowing
|
|
2321
|
+
* const filtered = await users.aggregate()
|
|
2322
|
+
* .match<{ role: 'engineer' }>({ role: 'engineer' })
|
|
2323
|
+
* .toArray()
|
|
2324
|
+
* // filtered[0].role → 'engineer'
|
|
2325
|
+
*
|
|
2326
|
+
* // Automatic narrowing with $in (requires as const)
|
|
2327
|
+
* const subset = await users.aggregate()
|
|
2328
|
+
* .match({ role: { $in: ['engineer', 'designer'] as const } })
|
|
2329
|
+
* .toArray()
|
|
2330
|
+
* // subset[0].role → 'engineer' | 'designer'
|
|
2331
|
+
* ```
|
|
2332
|
+
*/
|
|
2333
|
+
match<TNarrow extends {
|
|
2334
|
+
[K in keyof TNarrow]: K extends keyof TOutput ? TOutput[K] : never;
|
|
2335
|
+
} = {}, F extends TypedFilter<TOutput> = TypedFilter<TOutput>>(filter: F): AggregatePipeline<TDef, Prettify<Omit<NarrowFromFilter<TOutput, F>, keyof TNarrow> & TNarrow>>;
|
|
2336
|
+
/**
|
|
2337
|
+
* Sort documents by one or more fields.
|
|
2338
|
+
*
|
|
2339
|
+
* Appends a `$sort` stage. Keys are constrained to `keyof TOutput & string`
|
|
2340
|
+
* and values must be `1` (ascending) or `-1` (descending).
|
|
2341
|
+
*
|
|
2342
|
+
* @param spec - A sort specification mapping field names to sort direction.
|
|
2343
|
+
* @returns A new pipeline with the `$sort` stage appended.
|
|
2344
|
+
*
|
|
2345
|
+
* @example
|
|
2346
|
+
* ```ts
|
|
2347
|
+
* const sorted = await aggregate(users)
|
|
2348
|
+
* .sort({ age: -1, name: 1 })
|
|
2349
|
+
* .toArray()
|
|
2350
|
+
* ```
|
|
2351
|
+
*/
|
|
2352
|
+
sort(spec: Partial<Record<keyof TOutput & string, 1 | -1>>): AggregatePipeline<TDef, TOutput>;
|
|
2353
|
+
/**
|
|
2354
|
+
* Skip a number of documents in the pipeline.
|
|
2355
|
+
*
|
|
2356
|
+
* Appends a `$skip` stage. Commonly used with {@link limit} for pagination.
|
|
2357
|
+
*
|
|
2358
|
+
* @param n - The number of documents to skip.
|
|
2359
|
+
* @returns A new pipeline with the `$skip` stage appended.
|
|
2360
|
+
*
|
|
2361
|
+
* @example
|
|
2362
|
+
* ```ts
|
|
2363
|
+
* // Page 2 (10 items per page)
|
|
2364
|
+
* const page2 = await aggregate(users)
|
|
2365
|
+
* .sort({ name: 1 })
|
|
2366
|
+
* .skip(10)
|
|
2367
|
+
* .limit(10)
|
|
2368
|
+
* .toArray()
|
|
2369
|
+
* ```
|
|
2370
|
+
*/
|
|
2371
|
+
skip(n: number): AggregatePipeline<TDef, TOutput>;
|
|
2372
|
+
/**
|
|
2373
|
+
* Limit the number of documents passing through the pipeline.
|
|
2374
|
+
*
|
|
2375
|
+
* Appends a `$limit` stage. Commonly used with {@link skip} for pagination,
|
|
2376
|
+
* or after {@link sort} to get top/bottom N results.
|
|
2377
|
+
*
|
|
2378
|
+
* @param n - The maximum number of documents to pass through.
|
|
2379
|
+
* @returns A new pipeline with the `$limit` stage appended.
|
|
2380
|
+
*
|
|
2381
|
+
* @example
|
|
2382
|
+
* ```ts
|
|
2383
|
+
* const top5 = await aggregate(users)
|
|
2384
|
+
* .sort({ score: -1 })
|
|
2385
|
+
* .limit(5)
|
|
2386
|
+
* .toArray()
|
|
2387
|
+
* ```
|
|
2388
|
+
*/
|
|
2389
|
+
limit(n: number): AggregatePipeline<TDef, TOutput>;
|
|
2390
|
+
/**
|
|
2391
|
+
* Include only specified fields in the output.
|
|
2392
|
+
*
|
|
2393
|
+
* Appends a `$project` stage with inclusion (`1`) for each key.
|
|
2394
|
+
* The `_id` field is always included. The output type narrows to
|
|
2395
|
+
* `Pick<TOutput, K | '_id'>`.
|
|
2396
|
+
*
|
|
2397
|
+
* @param spec - An object mapping field names to `1` for inclusion.
|
|
2398
|
+
* @returns A new pipeline with the `$project` stage appended.
|
|
2399
|
+
*
|
|
2400
|
+
* @example
|
|
2401
|
+
* ```ts
|
|
2402
|
+
* const namesOnly = await aggregate(users)
|
|
2403
|
+
* .project({ name: 1 })
|
|
2404
|
+
* .toArray()
|
|
2405
|
+
* // [{ _id: ..., name: 'Ada' }, ...]
|
|
2406
|
+
* ```
|
|
2407
|
+
*/
|
|
2408
|
+
project<K extends keyof TOutput & string>(spec: Record<K, 1>): AggregatePipeline<TDef, Prettify<Pick<TOutput, K | ('_id' extends keyof TOutput ? '_id' : never)>>>;
|
|
2409
|
+
/**
|
|
2410
|
+
* Variadic shorthand for {@link project} — pick fields to include.
|
|
1305
2411
|
*
|
|
1306
|
-
*
|
|
1307
|
-
*
|
|
1308
|
-
*
|
|
1309
|
-
* @
|
|
2412
|
+
* Generates a `$project` stage that includes only the listed fields
|
|
2413
|
+
* (plus `_id`). Equivalent to `.project({ field1: 1, field2: 1 })`.
|
|
2414
|
+
*
|
|
2415
|
+
* @param fields - Field names to include in the output.
|
|
2416
|
+
* @returns A new pipeline with the `$project` stage appended.
|
|
1310
2417
|
*
|
|
1311
2418
|
* @example
|
|
1312
2419
|
* ```ts
|
|
1313
|
-
* const
|
|
1314
|
-
*
|
|
1315
|
-
*
|
|
2420
|
+
* const namesAndRoles = await aggregate(users)
|
|
2421
|
+
* .pick('name', 'role')
|
|
2422
|
+
* .toArray()
|
|
1316
2423
|
* ```
|
|
1317
2424
|
*/
|
|
1318
|
-
|
|
2425
|
+
pick<K extends keyof TOutput & string>(...fields: K[]): AggregatePipeline<TDef, Prettify<Pick<TOutput, K | ('_id' extends keyof TOutput ? '_id' : never)>>>;
|
|
1319
2426
|
/**
|
|
1320
|
-
*
|
|
2427
|
+
* Exclude specified fields from the output.
|
|
1321
2428
|
*
|
|
1322
|
-
*
|
|
1323
|
-
*
|
|
2429
|
+
* Appends a `$project` stage with exclusion (`0`) for each key.
|
|
2430
|
+
* All other fields pass through. The output type becomes `Omit<TOutput, K>`.
|
|
1324
2431
|
*
|
|
1325
|
-
* @param
|
|
1326
|
-
* @
|
|
1327
|
-
* @returns The matched document (never null).
|
|
1328
|
-
* @throws {ZodmonNotFoundError} When no document matches the filter.
|
|
1329
|
-
* @throws {ZodmonValidationError} When the fetched document fails schema validation in strict mode.
|
|
2432
|
+
* @param fields - Field names to exclude from the output.
|
|
2433
|
+
* @returns A new pipeline with the `$project` stage appended.
|
|
1330
2434
|
*
|
|
1331
2435
|
* @example
|
|
1332
2436
|
* ```ts
|
|
1333
|
-
* const
|
|
1334
|
-
*
|
|
1335
|
-
*
|
|
2437
|
+
* const noAge = await aggregate(users)
|
|
2438
|
+
* .omit('age')
|
|
2439
|
+
* .toArray()
|
|
1336
2440
|
* ```
|
|
1337
2441
|
*/
|
|
1338
|
-
|
|
2442
|
+
omit<K extends keyof TOutput & string>(...fields: K[]): AggregatePipeline<TDef, Prettify<Omit<TOutput, K>>>;
|
|
1339
2443
|
/**
|
|
1340
|
-
*
|
|
2444
|
+
* Group documents by one or more fields with accumulator expressions.
|
|
1341
2445
|
*
|
|
1342
|
-
*
|
|
1343
|
-
* (`toArray`, `for await`) is called. Use `sort`, `skip`, and `limit`
|
|
1344
|
-
* to shape the query before executing.
|
|
2446
|
+
* Accepts accumulators as either a **callback** (recommended) or a plain object.
|
|
1345
2447
|
*
|
|
1346
|
-
*
|
|
1347
|
-
*
|
|
1348
|
-
*
|
|
2448
|
+
* The callback receives a typed `AccumulatorBuilder` with full autocomplete
|
|
2449
|
+
* and compile-time field validation. Builder methods resolve return types
|
|
2450
|
+
* to the actual field type (`T[K]`), not `unknown`.
|
|
2451
|
+
*
|
|
2452
|
+
* @param field - A field name or array of field names to group by.
|
|
2453
|
+
* @param accumulators - A callback `(acc) => ({ ... })` or plain accumulator object.
|
|
2454
|
+
* @returns A new pipeline with the `$group` stage appended.
|
|
1349
2455
|
*
|
|
1350
2456
|
* @example
|
|
1351
2457
|
* ```ts
|
|
1352
|
-
*
|
|
1353
|
-
* const
|
|
1354
|
-
* .
|
|
1355
|
-
*
|
|
2458
|
+
* // Callback style (recommended — full type safety)
|
|
2459
|
+
* const byRole = await aggregate(users)
|
|
2460
|
+
* .groupBy('role', acc => ({
|
|
2461
|
+
* count: acc.count(),
|
|
2462
|
+
* minSalary: acc.min('salary'), // → number
|
|
2463
|
+
* firstName: acc.first('name'), // → string
|
|
2464
|
+
* }))
|
|
2465
|
+
* .toArray()
|
|
2466
|
+
* ```
|
|
2467
|
+
*
|
|
2468
|
+
* @example
|
|
2469
|
+
* ```ts
|
|
2470
|
+
* // Object style (backward compatible)
|
|
2471
|
+
* const byRole = await aggregate(users)
|
|
2472
|
+
* .groupBy('role', { count: $count() })
|
|
2473
|
+
* .toArray()
|
|
2474
|
+
* ```
|
|
2475
|
+
*
|
|
2476
|
+
* @example
|
|
2477
|
+
* ```ts
|
|
2478
|
+
* // Compound groupBy
|
|
2479
|
+
* const byRoleAndDept = await aggregate(users)
|
|
2480
|
+
* .groupBy(['role', 'dept'], acc => ({ count: acc.count() }))
|
|
1356
2481
|
* .toArray()
|
|
1357
2482
|
* ```
|
|
1358
2483
|
*/
|
|
1359
|
-
|
|
2484
|
+
groupBy<K extends keyof TOutput & string, TAccum extends Record<string, Accumulator>>(field: K, accumulators: ((acc: AccumulatorBuilder<TOutput>) => TAccum) | TAccum): AggregatePipeline<TDef, GroupByResult<TOutput, K, TAccum>>;
|
|
2485
|
+
groupBy<K extends keyof TOutput & string, TAccum extends Record<string, Accumulator>>(field: K[], accumulators: ((acc: AccumulatorBuilder<TOutput>) => TAccum) | TAccum): AggregatePipeline<TDef, GroupByCompoundResult<TOutput, K, TAccum>>;
|
|
1360
2486
|
/**
|
|
1361
|
-
*
|
|
2487
|
+
* Add new fields or overwrite existing ones in the output documents.
|
|
1362
2488
|
*
|
|
1363
|
-
*
|
|
1364
|
-
*
|
|
1365
|
-
* at the field-operator level through {@link TypedUpdateFilter}.
|
|
2489
|
+
* **Callback style (recommended)** — the `ExpressionBuilder` provides
|
|
2490
|
+
* autocomplete for field names and infers return types automatically:
|
|
1366
2491
|
*
|
|
1367
|
-
*
|
|
1368
|
-
*
|
|
1369
|
-
*
|
|
1370
|
-
*
|
|
2492
|
+
* ```ts
|
|
2493
|
+
* employees.aggregate()
|
|
2494
|
+
* .addFields(expr => ({
|
|
2495
|
+
* hireYear: expr.year('hiredAt'), // Expression<number>
|
|
2496
|
+
* isHighPay: expr.gte('salary', 100_000), // Expression<boolean>
|
|
2497
|
+
* }))
|
|
2498
|
+
* ```
|
|
2499
|
+
*
|
|
2500
|
+
* **Raw style** — pass MongoDB expression objects directly. Use an
|
|
2501
|
+
* explicit type parameter to preserve type safety:
|
|
2502
|
+
*
|
|
2503
|
+
* ```ts
|
|
2504
|
+
* // Tier 2: explicit type parameter
|
|
2505
|
+
* .addFields<{ hireYear: number }>({ hireYear: { $year: '$hiredAt' } })
|
|
2506
|
+
*
|
|
2507
|
+
* // Tier 3: no type parameter — fields resolve to unknown
|
|
2508
|
+
* .addFields({ hireYear: { $year: '$hiredAt' } })
|
|
2509
|
+
* ```
|
|
2510
|
+
*
|
|
2511
|
+
* @param fields - A callback `(expr) => ({ ... })` or plain fields object.
|
|
2512
|
+
* @returns A new pipeline with the `$addFields` stage appended.
|
|
1371
2513
|
*
|
|
1372
2514
|
* @example
|
|
1373
2515
|
* ```ts
|
|
1374
|
-
* const
|
|
1375
|
-
*
|
|
1376
|
-
*
|
|
2516
|
+
* const enriched = await aggregate(employees)
|
|
2517
|
+
* .addFields(expr => ({
|
|
2518
|
+
* hireYear: expr.year('hiredAt'),
|
|
2519
|
+
* monthlySalary: expr.divide('salary', 12),
|
|
2520
|
+
* }))
|
|
2521
|
+
* .toArray()
|
|
1377
2522
|
* ```
|
|
1378
2523
|
*/
|
|
1379
|
-
|
|
2524
|
+
addFields<TFields extends Record<string, Expression>>(fields: (expr: ExpressionBuilder<TOutput>) => TFields): AggregatePipeline<TDef, Prettify<TOutput & InferAddedFields<TFields>>>;
|
|
2525
|
+
addFields<TFields extends Record<string, unknown> = Record<string, unknown>>(fields: TFields): AggregatePipeline<TDef, Prettify<TOutput & TFields>>;
|
|
1380
2526
|
/**
|
|
1381
|
-
*
|
|
2527
|
+
* Deconstruct an array field, outputting one document per array element.
|
|
1382
2528
|
*
|
|
1383
|
-
*
|
|
1384
|
-
*
|
|
1385
|
-
*
|
|
2529
|
+
* Appends an `$unwind` stage. The unwound field's type changes from
|
|
2530
|
+
* `T[]` to `T` in the output type. Documents with empty or missing
|
|
2531
|
+
* arrays are dropped unless `preserveEmpty` is `true`.
|
|
1386
2532
|
*
|
|
1387
|
-
* @param
|
|
1388
|
-
* @param
|
|
1389
|
-
* @param options -
|
|
1390
|
-
* @returns
|
|
2533
|
+
* @param field - The name of the array field to unwind.
|
|
2534
|
+
* @param options - Optional settings for the unwind stage.
|
|
2535
|
+
* @param options.preserveEmpty - If `true`, documents with null, missing, or empty arrays are preserved.
|
|
2536
|
+
* @returns A new pipeline with the `$unwind` stage appended.
|
|
1391
2537
|
*
|
|
1392
2538
|
* @example
|
|
1393
2539
|
* ```ts
|
|
1394
|
-
* const
|
|
1395
|
-
*
|
|
1396
|
-
*
|
|
2540
|
+
* const flat = await aggregate(orders)
|
|
2541
|
+
* .unwind('items')
|
|
2542
|
+
* .toArray()
|
|
2543
|
+
* // Each result has a single `items` value instead of an array
|
|
1397
2544
|
* ```
|
|
1398
2545
|
*/
|
|
1399
|
-
|
|
2546
|
+
unwind<K extends keyof TOutput & string>(field: K, options?: {
|
|
2547
|
+
preserveEmpty?: boolean;
|
|
2548
|
+
}): AggregatePipeline<TDef, UnwindResult<TOutput, K>>;
|
|
1400
2549
|
/**
|
|
1401
|
-
*
|
|
2550
|
+
* Join documents from another collection via a `$lookup` stage.
|
|
1402
2551
|
*
|
|
1403
|
-
*
|
|
1404
|
-
*
|
|
1405
|
-
*
|
|
1406
|
-
* resolution logic as {@link findOne}.
|
|
2552
|
+
* **Forward lookup** — when the field has `.ref()` metadata pointing to
|
|
2553
|
+
* another collection, resolves the target collection and output type
|
|
2554
|
+
* automatically:
|
|
1407
2555
|
*
|
|
1408
|
-
*
|
|
1409
|
-
*
|
|
1410
|
-
*
|
|
1411
|
-
*
|
|
1412
|
-
*
|
|
2556
|
+
* ```ts
|
|
2557
|
+
* books.aggregate().lookup('authorId').toArray()
|
|
2558
|
+
* // Each book gains an `authors: Author[]` array
|
|
2559
|
+
* ```
|
|
2560
|
+
*
|
|
2561
|
+
* **Reverse lookup** — when the foreign key lives on the *other*
|
|
2562
|
+
* collection, pass the collection definition and the `on` field:
|
|
2563
|
+
*
|
|
2564
|
+
* ```ts
|
|
2565
|
+
* users.aggregate().lookup(Books, { on: 'authorId' }).toArray()
|
|
2566
|
+
* // Each user gains a `books: Book[]` array
|
|
2567
|
+
* ```
|
|
2568
|
+
*
|
|
2569
|
+
* Pass `unwind: true` to flatten the joined array into a single object
|
|
2570
|
+
* (adds a `$unwind` stage with `preserveNullAndEmptyArrays: true`).
|
|
2571
|
+
*
|
|
2572
|
+
* @param fieldOrCollection - A ref-bearing field name (forward) or collection definition (reverse).
|
|
2573
|
+
* @param options - `as` alias, `unwind` flag, and `on` (reverse only).
|
|
2574
|
+
* @returns A new pipeline with `$lookup` (and optionally `$unwind`) appended.
|
|
1413
2575
|
*
|
|
1414
2576
|
* @example
|
|
1415
2577
|
* ```ts
|
|
1416
|
-
*
|
|
1417
|
-
* const
|
|
1418
|
-
* {
|
|
1419
|
-
*
|
|
1420
|
-
*
|
|
1421
|
-
*
|
|
2578
|
+
* // Forward lookup with custom alias and unwind
|
|
2579
|
+
* const results = await aggregate(books)
|
|
2580
|
+
* .lookup('authorId', { as: 'author', unwind: true })
|
|
2581
|
+
* .toArray()
|
|
2582
|
+
* // Each book has a single `author: Author` object
|
|
2583
|
+
* ```
|
|
2584
|
+
*
|
|
2585
|
+
* @example
|
|
2586
|
+
* ```ts
|
|
2587
|
+
* // Reverse lookup: each author gains their books
|
|
2588
|
+
* const results = await aggregate(authors)
|
|
2589
|
+
* .lookup(Books, { on: 'authorId' })
|
|
2590
|
+
* .toArray()
|
|
2591
|
+
* // Each author has a `books: Book[]` array
|
|
1422
2592
|
* ```
|
|
1423
2593
|
*/
|
|
1424
|
-
|
|
2594
|
+
lookup<K extends RefFields<TDef>, TAs extends string = CollectionName<ExtractRefCollection<TDef, K>>>(field: K, options: {
|
|
2595
|
+
as?: TAs;
|
|
2596
|
+
unwind: true;
|
|
2597
|
+
}): AggregatePipeline<TDef, Prettify<TOutput & {
|
|
2598
|
+
[P in TAs]: InferDocument<ExtractRefCollection<TDef, K>>;
|
|
2599
|
+
}>>;
|
|
2600
|
+
lookup<K extends RefFields<TDef>, TAs extends string = CollectionName<ExtractRefCollection<TDef, K>>>(field: K, options?: {
|
|
2601
|
+
as?: TAs;
|
|
2602
|
+
unwind?: false;
|
|
2603
|
+
}): AggregatePipeline<TDef, Prettify<TOutput & {
|
|
2604
|
+
[P in TAs]: InferDocument<ExtractRefCollection<TDef, K>>[];
|
|
2605
|
+
}>>;
|
|
2606
|
+
lookup<TForeignDef extends AnyCollection, TAs extends string = CollectionName<TForeignDef>>(from: TForeignDef, options: {
|
|
2607
|
+
on: keyof InferDocument<TForeignDef> & string;
|
|
2608
|
+
as?: TAs;
|
|
2609
|
+
unwind: true;
|
|
2610
|
+
}): AggregatePipeline<TDef, Prettify<TOutput & {
|
|
2611
|
+
[P in TAs]: InferDocument<TForeignDef>;
|
|
2612
|
+
}>>;
|
|
2613
|
+
lookup<TForeignDef extends AnyCollection, TAs extends string = CollectionName<TForeignDef>>(from: TForeignDef, options: {
|
|
2614
|
+
on: keyof InferDocument<TForeignDef> & string;
|
|
2615
|
+
as?: TAs;
|
|
2616
|
+
unwind?: false;
|
|
2617
|
+
}): AggregatePipeline<TDef, Prettify<TOutput & {
|
|
2618
|
+
[P in TAs]: InferDocument<TForeignDef>[];
|
|
2619
|
+
}>>;
|
|
1425
2620
|
/**
|
|
1426
|
-
*
|
|
2621
|
+
* Count documents per group, sorted by count descending.
|
|
1427
2622
|
*
|
|
1428
|
-
*
|
|
1429
|
-
* No validation is performed — the document is deleted directly through
|
|
1430
|
-
* the MongoDB driver.
|
|
2623
|
+
* Shorthand for `.groupBy(field, { count: $count() }).sort({ count: -1 })`.
|
|
1431
2624
|
*
|
|
1432
|
-
* @param
|
|
1433
|
-
* @returns
|
|
2625
|
+
* @param field - The field to group and count by.
|
|
2626
|
+
* @returns A new pipeline producing `{ _id: TOutput[K], count: number }` results.
|
|
1434
2627
|
*
|
|
1435
2628
|
* @example
|
|
1436
2629
|
* ```ts
|
|
1437
|
-
* const
|
|
1438
|
-
*
|
|
1439
|
-
*
|
|
2630
|
+
* const roleCounts = await aggregate(users)
|
|
2631
|
+
* .countBy('role')
|
|
2632
|
+
* .toArray()
|
|
2633
|
+
* // [{ _id: 'user', count: 3 }, { _id: 'admin', count: 2 }]
|
|
1440
2634
|
* ```
|
|
1441
2635
|
*/
|
|
1442
|
-
|
|
2636
|
+
countBy<K extends keyof TOutput & string>(field: K): AggregatePipeline<TDef, Prettify<{
|
|
2637
|
+
_id: TOutput[K];
|
|
2638
|
+
count: number;
|
|
2639
|
+
}>>;
|
|
1443
2640
|
/**
|
|
1444
|
-
*
|
|
2641
|
+
* Sum a numeric field per group, sorted by total descending.
|
|
1445
2642
|
*
|
|
1446
|
-
*
|
|
1447
|
-
* No validation is performed — documents are deleted directly through
|
|
1448
|
-
* the MongoDB driver.
|
|
2643
|
+
* Shorthand for `.groupBy(field, { total: $sum('$sumField') }).sort({ total: -1 })`.
|
|
1449
2644
|
*
|
|
1450
|
-
* @param
|
|
1451
|
-
* @
|
|
2645
|
+
* @param field - The field to group by.
|
|
2646
|
+
* @param sumField - The numeric field to sum.
|
|
2647
|
+
* @returns A new pipeline producing `{ _id: TOutput[K], total: number }` results.
|
|
1452
2648
|
*
|
|
1453
2649
|
* @example
|
|
1454
2650
|
* ```ts
|
|
1455
|
-
* const
|
|
1456
|
-
*
|
|
1457
|
-
*
|
|
2651
|
+
* const revenueByCategory = await aggregate(orders)
|
|
2652
|
+
* .sumBy('category', 'amount')
|
|
2653
|
+
* .toArray()
|
|
2654
|
+
* // [{ _id: 'electronics', total: 5000 }, ...]
|
|
1458
2655
|
* ```
|
|
1459
2656
|
*/
|
|
1460
|
-
|
|
2657
|
+
sumBy<K extends keyof TOutput & string, S extends keyof TOutput & string>(field: K, sumField: S): AggregatePipeline<TDef, Prettify<{
|
|
2658
|
+
_id: TOutput[K];
|
|
2659
|
+
total: number;
|
|
2660
|
+
}>>;
|
|
1461
2661
|
/**
|
|
1462
|
-
*
|
|
2662
|
+
* Sort by a single field with a friendly direction name.
|
|
1463
2663
|
*
|
|
1464
|
-
*
|
|
1465
|
-
* The returned document is validated against the collection's Zod schema
|
|
1466
|
-
* using the same resolution logic as {@link findOne}.
|
|
2664
|
+
* Shorthand for `.sort({ [field]: direction === 'desc' ? -1 : 1 })`.
|
|
1467
2665
|
*
|
|
1468
|
-
* @param
|
|
1469
|
-
* @param
|
|
1470
|
-
* @returns
|
|
1471
|
-
* @throws {ZodmonValidationError} When the returned document fails schema validation in strict mode.
|
|
2666
|
+
* @param field - The field to sort by.
|
|
2667
|
+
* @param direction - Sort direction: `'asc'` (default) or `'desc'`.
|
|
2668
|
+
* @returns A new pipeline with the `$sort` stage appended.
|
|
1472
2669
|
*
|
|
1473
2670
|
* @example
|
|
1474
2671
|
* ```ts
|
|
1475
|
-
* const
|
|
1476
|
-
*
|
|
1477
|
-
*
|
|
2672
|
+
* const youngest = await aggregate(users)
|
|
2673
|
+
* .sortBy('age')
|
|
2674
|
+
* .toArray()
|
|
1478
2675
|
* ```
|
|
1479
2676
|
*/
|
|
1480
|
-
|
|
2677
|
+
sortBy(field: keyof TOutput & string, direction?: 'asc' | 'desc'): AggregatePipeline<TDef, TOutput>;
|
|
1481
2678
|
/**
|
|
1482
|
-
*
|
|
2679
|
+
* Return the top N documents sorted by a field descending.
|
|
1483
2680
|
*
|
|
1484
|
-
*
|
|
1485
|
-
* `.text()` / `.expireAfter()` and compound `indexes` in collection options)
|
|
1486
|
-
* with the indexes that currently exist in MongoDB, then creates, drops, or
|
|
1487
|
-
* reports differences depending on the options.
|
|
2681
|
+
* Shorthand for `.sort({ [by]: -1 }).limit(n)`.
|
|
1488
2682
|
*
|
|
1489
|
-
* @param
|
|
1490
|
-
* @
|
|
2683
|
+
* @param n - The number of documents to return.
|
|
2684
|
+
* @param options - An object with a `by` field specifying the sort key.
|
|
2685
|
+
* @returns A new pipeline with `$sort` and `$limit` stages appended.
|
|
1491
2686
|
*
|
|
1492
2687
|
* @example
|
|
1493
2688
|
* ```ts
|
|
1494
|
-
* const
|
|
1495
|
-
*
|
|
1496
|
-
*
|
|
1497
|
-
* console.log('Stale:', result.stale.map(s => s.name))
|
|
2689
|
+
* const top3 = await aggregate(users)
|
|
2690
|
+
* .top(3, { by: 'score' })
|
|
2691
|
+
* .toArray()
|
|
1498
2692
|
* ```
|
|
2693
|
+
*/
|
|
2694
|
+
top(n: number, options: {
|
|
2695
|
+
by: keyof TOutput & string;
|
|
2696
|
+
}): AggregatePipeline<TDef, TOutput>;
|
|
2697
|
+
/**
|
|
2698
|
+
* Return the bottom N documents sorted by a field ascending.
|
|
2699
|
+
*
|
|
2700
|
+
* Shorthand for `.sort({ [by]: 1 }).limit(n)`.
|
|
2701
|
+
*
|
|
2702
|
+
* @param n - The number of documents to return.
|
|
2703
|
+
* @param options - An object with a `by` field specifying the sort key.
|
|
2704
|
+
* @returns A new pipeline with `$sort` and `$limit` stages appended.
|
|
1499
2705
|
*
|
|
1500
2706
|
* @example
|
|
1501
2707
|
* ```ts
|
|
1502
|
-
*
|
|
1503
|
-
*
|
|
1504
|
-
*
|
|
1505
|
-
* console.log('Would drop:', diff.dropped)
|
|
2708
|
+
* const bottom3 = await aggregate(users)
|
|
2709
|
+
* .bottom(3, { by: 'score' })
|
|
2710
|
+
* .toArray()
|
|
1506
2711
|
* ```
|
|
1507
2712
|
*/
|
|
1508
|
-
|
|
2713
|
+
bottom(n: number, options: {
|
|
2714
|
+
by: keyof TOutput & string;
|
|
2715
|
+
}): AggregatePipeline<TDef, TOutput>;
|
|
1509
2716
|
}
|
|
2717
|
+
/**
|
|
2718
|
+
* Create a new aggregation pipeline for a collection.
|
|
2719
|
+
*
|
|
2720
|
+
* Returns an empty pipeline that can be extended with stage methods
|
|
2721
|
+
* like `raw()`, or future typed stages (`match`, `project`, etc.).
|
|
2722
|
+
*
|
|
2723
|
+
* @param handle - A typed collection handle obtained from `db.use()`.
|
|
2724
|
+
* @returns A new empty `AggregatePipeline` whose output type is the collection's document type.
|
|
2725
|
+
*
|
|
2726
|
+
* @example
|
|
2727
|
+
* ```ts
|
|
2728
|
+
* const users = db.use(Users)
|
|
2729
|
+
* const admins = await aggregate(users)
|
|
2730
|
+
* .raw({ $match: { role: 'admin' } })
|
|
2731
|
+
* .toArray()
|
|
2732
|
+
* ```
|
|
2733
|
+
*/
|
|
2734
|
+
declare function aggregate<TDef extends AnyCollection>(handle: CollectionHandle<TDef>): AggregatePipeline<TDef, InferDocument<TDef>>;
|
|
1510
2735
|
|
|
1511
2736
|
/**
|
|
1512
2737
|
* Wraps a MongoDB `MongoClient` and `Db`, providing typed collection access
|
|
@@ -1540,7 +2765,7 @@ declare class Database {
|
|
|
1540
2765
|
* @param def - A collection definition created by `collection()`.
|
|
1541
2766
|
* @returns A typed collection handle for CRUD operations.
|
|
1542
2767
|
*/
|
|
1543
|
-
use<TShape extends z.core.$ZodShape, TIndexes extends readonly CompoundIndexDefinition<Extract<keyof TShape, string>>[] = readonly CompoundIndexDefinition<Extract<keyof TShape, string>>[]>(def: CollectionDefinition<TShape, TIndexes>): CollectionHandle<CollectionDefinition<TShape, TIndexes>>;
|
|
2768
|
+
use<TName extends string, TShape extends z.core.$ZodShape, TIndexes extends readonly CompoundIndexDefinition<Extract<keyof TShape, string>>[] = readonly CompoundIndexDefinition<Extract<keyof TShape, string>>[]>(def: CollectionDefinition<TName, TShape, TIndexes>): CollectionHandle<CollectionDefinition<TName, TShape, TIndexes>>;
|
|
1544
2769
|
/**
|
|
1545
2770
|
* Synchronize indexes for all registered collections with MongoDB.
|
|
1546
2771
|
*
|
|
@@ -1636,9 +2861,9 @@ declare function extractFieldIndexes(shape: z.core.$ZodShape): FieldIndexDefinit
|
|
|
1636
2861
|
* })
|
|
1637
2862
|
* ```
|
|
1638
2863
|
*/
|
|
1639
|
-
declare function collection<TShape extends z.core.$ZodShape, const TIndexes extends readonly CompoundIndexDefinition<Extract<keyof TShape, string>>[] = readonly CompoundIndexDefinition<Extract<keyof TShape, string>>[]>(name:
|
|
2864
|
+
declare function collection<TName extends string, TShape extends z.core.$ZodShape, const TIndexes extends readonly CompoundIndexDefinition<Extract<keyof TShape, string>>[] = readonly CompoundIndexDefinition<Extract<keyof TShape, string>>[]>(name: TName, shape: TShape, options?: Omit<CollectionOptions<Extract<keyof TShape, string>>, 'indexes'> & {
|
|
1640
2865
|
indexes?: TIndexes;
|
|
1641
|
-
}): CollectionDefinition<TShape, [...TIndexes]>;
|
|
2866
|
+
}): CollectionDefinition<TName, TShape, [...TIndexes]>;
|
|
1642
2867
|
|
|
1643
2868
|
type IndexDirection = 1 | -1;
|
|
1644
2869
|
type CompoundIndexOptions = NonNullable<CompoundIndexDefinition['options']>;
|
|
@@ -2111,11 +3336,11 @@ declare const $: {
|
|
|
2111
3336
|
readonly lte: <V>(value: V) => {
|
|
2112
3337
|
$lte: V;
|
|
2113
3338
|
};
|
|
2114
|
-
readonly in: <V>(values: V[]) => {
|
|
2115
|
-
$in: V[];
|
|
3339
|
+
readonly in: <V>(values: readonly V[]) => {
|
|
3340
|
+
$in: readonly V[];
|
|
2116
3341
|
};
|
|
2117
|
-
readonly nin: <V>(values: V[]) => {
|
|
2118
|
-
$nin: V[];
|
|
3342
|
+
readonly nin: <V>(values: readonly V[]) => {
|
|
3343
|
+
$nin: readonly V[];
|
|
2119
3344
|
};
|
|
2120
3345
|
readonly exists: (flag?: boolean) => {
|
|
2121
3346
|
$exists: boolean;
|
|
@@ -2207,8 +3432,8 @@ declare const $lte: <V>(value: V) => {
|
|
|
2207
3432
|
* users.find({ role: $in(['admin', 'moderator']) })
|
|
2208
3433
|
* ```
|
|
2209
3434
|
*/
|
|
2210
|
-
declare const $in: <V>(values: V[]) => {
|
|
2211
|
-
$in: V[];
|
|
3435
|
+
declare const $in: <V>(values: readonly V[]) => {
|
|
3436
|
+
$in: readonly V[];
|
|
2212
3437
|
};
|
|
2213
3438
|
/**
|
|
2214
3439
|
* Matches none of the values in the specified array.
|
|
@@ -2218,8 +3443,8 @@ declare const $in: <V>(values: V[]) => {
|
|
|
2218
3443
|
* users.find({ role: $nin(['banned', 'suspended']) })
|
|
2219
3444
|
* ```
|
|
2220
3445
|
*/
|
|
2221
|
-
declare const $nin: <V>(values: V[]) => {
|
|
2222
|
-
$nin: V[];
|
|
3446
|
+
declare const $nin: <V>(values: readonly V[]) => {
|
|
3447
|
+
$nin: readonly V[];
|
|
2223
3448
|
};
|
|
2224
3449
|
/**
|
|
2225
3450
|
* Matches documents where the field exists (or does not exist).
|
|
@@ -2319,84 +3544,6 @@ declare const $nor: <T>(...filters: NoInfer<TypedFilter<T>>[]) => TypedFilter<T>
|
|
|
2319
3544
|
*/
|
|
2320
3545
|
declare const raw: <T = any>(filter: Record<string, unknown>) => TypedFilter<T>;
|
|
2321
3546
|
|
|
2322
|
-
/**
|
|
2323
|
-
* Type-level marker that carries the target collection type through the
|
|
2324
|
-
* type system. Intersected with the schema return type by `.ref()` so
|
|
2325
|
-
* that `RefFields<T>` (future) can extract ref relationships.
|
|
2326
|
-
*
|
|
2327
|
-
* This is a phantom brand — no runtime value has this property.
|
|
2328
|
-
*/
|
|
2329
|
-
type RefMarker<TCollection extends AnyCollection = AnyCollection> = {
|
|
2330
|
-
readonly _ref: TCollection;
|
|
2331
|
-
};
|
|
2332
|
-
/**
|
|
2333
|
-
* Metadata stored in the WeakMap sidecar for schemas marked with `.ref()`.
|
|
2334
|
-
* Holds a reference to the target collection definition object.
|
|
2335
|
-
*/
|
|
2336
|
-
type RefMetadata = {
|
|
2337
|
-
readonly collection: AnyCollection;
|
|
2338
|
-
};
|
|
2339
|
-
/**
|
|
2340
|
-
* Module augmentation: adds `.ref()` to all `ZodType` schemas.
|
|
2341
|
-
*
|
|
2342
|
-
* The intersection constraint `this['_zod']['output'] extends InferDocument<TCollection>['_id']`
|
|
2343
|
-
* ensures compile-time type safety: the field's output type must match the
|
|
2344
|
-
* target collection's `_id` type. Mismatches produce a type error.
|
|
2345
|
-
*
|
|
2346
|
-
* Supports both default ObjectId `_id` and custom `_id` types (string, nanoid, etc.):
|
|
2347
|
-
* - `objectId().ref(Users)` compiles when Users has ObjectId `_id`
|
|
2348
|
-
* - `z.string().ref(Orgs)` compiles when Orgs has string `_id`
|
|
2349
|
-
* - `z.string().ref(Users)` is a type error (string ≠ ObjectId)
|
|
2350
|
-
* - `objectId().ref(Orgs)` is a type error (ObjectId ≠ string)
|
|
2351
|
-
*/
|
|
2352
|
-
declare module 'zod' {
|
|
2353
|
-
interface ZodType {
|
|
2354
|
-
/**
|
|
2355
|
-
* Declare a typed foreign key reference to another collection.
|
|
2356
|
-
*
|
|
2357
|
-
* Stores the target collection definition in metadata for runtime
|
|
2358
|
-
* populate resolution, and brands the return type with
|
|
2359
|
-
* `RefMarker<TCollection>` so `RefFields<T>` can extract refs
|
|
2360
|
-
* at the type level.
|
|
2361
|
-
*
|
|
2362
|
-
* The field's output type must match the target collection's `_id` type.
|
|
2363
|
-
* Mismatched types produce a compile error.
|
|
2364
|
-
*
|
|
2365
|
-
* Apply `.ref()` before wrapper methods like `.optional()` or `.nullable()`:
|
|
2366
|
-
* `objectId().ref(Users).optional()` — not `objectId().optional().ref(Users)`.
|
|
2367
|
-
*
|
|
2368
|
-
* @param collection - The target collection definition object.
|
|
2369
|
-
* @returns The same schema instance, branded with the ref marker.
|
|
2370
|
-
*
|
|
2371
|
-
* @example
|
|
2372
|
-
* ```ts
|
|
2373
|
-
* const Posts = collection('posts', {
|
|
2374
|
-
* authorId: objectId().ref(Users),
|
|
2375
|
-
* title: z.string(),
|
|
2376
|
-
* })
|
|
2377
|
-
* ```
|
|
2378
|
-
*/
|
|
2379
|
-
ref<TCollection extends AnyCollection>(collection: TCollection & (this['_zod']['output'] extends InferDocument<TCollection>['_id'] ? unknown : never)): this & RefMarker<TCollection>;
|
|
2380
|
-
}
|
|
2381
|
-
}
|
|
2382
|
-
/**
|
|
2383
|
-
* Retrieve the ref metadata attached to a Zod schema, if any.
|
|
2384
|
-
*
|
|
2385
|
-
* Returns `undefined` when the schema was never marked with `.ref()`.
|
|
2386
|
-
*
|
|
2387
|
-
* @param schema - The Zod schema to inspect. Accepts `unknown` for
|
|
2388
|
-
* convenience; non-object values safely return `undefined`.
|
|
2389
|
-
* @returns The {@link RefMetadata} for the schema, or `undefined`.
|
|
2390
|
-
*
|
|
2391
|
-
* @example
|
|
2392
|
-
* ```ts
|
|
2393
|
-
* const authorId = objectId().ref(Users)
|
|
2394
|
-
* const meta = getRefMetadata(authorId)
|
|
2395
|
-
* // => { collection: Users }
|
|
2396
|
-
* ```
|
|
2397
|
-
*/
|
|
2398
|
-
declare function getRefMetadata(schema: unknown): RefMetadata | undefined;
|
|
2399
|
-
|
|
2400
3547
|
/**
|
|
2401
3548
|
* Shorthand for `CollectionHandle<TDef>`.
|
|
2402
3549
|
*
|
|
@@ -2462,4 +3609,4 @@ type UpdateFilterOf<TDef extends AnyCollection> = TypedUpdateFilter<InferDocumen
|
|
|
2462
3609
|
*/
|
|
2463
3610
|
type SortOf<TDef extends AnyCollection> = TypedSort<InferDocument<TDef>>;
|
|
2464
3611
|
|
|
2465
|
-
export { $, $and, $eq, $exists, $gt, $gte, $in, $lt, $lte, $ne, $nin, $nor, $not, $or, $regex, type AddToSetEach, type AddToSetFields, type AnyCollection, type ArrayElement, type CollectionDefinition, CollectionHandle, type CollectionOptions, type ComparisonOperators, type CompoundIndexDefinition, type CurrentDateFields, type CursorPage, type CursorPaginateOptions, Database, type DotPathType, type DotPaths, type FieldIndexDefinition, type FilterOf, type FindOneAndDeleteOptions, type FindOneAndUpdateOptions, type FindOneOptions, type FindOptions, type HandleOf, type IncFields, IndexBuilder, type IndexMetadata, type IndexNames, type IndexOptions, type IndexSpec, type InferDocument, type InferInsert, type OffsetPage, type OffsetPaginateOptions, type PopFields, type PullFields, type PushFields, type PushModifiers, type RefMarker, type RefMetadata, type RenameFields, type ResolvedShape, type SetFields, type SortOf, type StaleIndex, type SyncIndexesOptions, type SyncIndexesResult, type TypedFilter, TypedFindCursor, type TypedSort, type TypedUpdateFilter, type UnsetFields, type UpdateFilterOf, type UpdateOptions, type ValidationMode, type ZodObjectId, ZodmonNotFoundError, ZodmonValidationError, checkUnindexedFields, collection, createClient, deleteMany, deleteOne, extractComparableOptions, extractDbName, extractFieldIndexes, find, findOne, findOneAndDelete, findOneAndUpdate, findOneOrThrow, generateIndexName, getIndexMetadata, getRefMetadata, index, insertMany, insertOne, isOid, objectId, oid, raw, serializeIndexKey, syncIndexes, toCompoundIndexSpec, toFieldIndexSpec, updateMany, updateOne };
|
|
3612
|
+
export { $, $addToSet, $and, $avg, $count, $eq, $exists, $first, $gt, $gte, $in, $last, $lt, $lte, $max, $min, $ne, $nin, $nor, $not, $or, $push, $regex, $sum, type Accumulator, type AccumulatorBuilder, type AddToSetEach, type AddToSetFields, AggregatePipeline, type AnyCollection, type ArrayElement, type CollectionDefinition, CollectionHandle, type CollectionName, type CollectionOptions, type ComparisonOperators, type CompoundIndexDefinition, type CurrentDateFields, type CursorPage, type CursorPaginateOptions, Database, type DotPathType, type DotPaths, type Expression, type ExpressionBuilder, type ExtractRefCollection, type FieldIndexDefinition, type FieldRef, type FieldRefType, type FilterOf, type FindOneAndDeleteOptions, type FindOneAndUpdateOptions, type FindOneOptions, type FindOptions, type GroupByCompoundResult, type GroupByResult, type HandleOf, type IncFields, IndexBuilder, type IndexMetadata, type IndexNames, type IndexOptions, type IndexSpec, type InferAccumulator, type InferAccumulators, type InferAddedFields, type InferDocument, type InferExpression, type InferInsert, type NarrowFromFilter, type OffsetPage, type OffsetPaginateOptions, type PopFields, type Prettify, type PullFields, type PushFields, type PushModifiers, type RefFields, type RefMarker, type RefMetadata, type RenameFields, type ResolvedShape, type SetFields, type SortOf, type StaleIndex, type SyncIndexesOptions, type SyncIndexesResult, type TypedFilter, TypedFindCursor, type TypedSort, type TypedUpdateFilter, type UnsetFields, type UnwindResult, type UpdateFilterOf, type UpdateOptions, type ValidationMode, type ZodObjectId, ZodmonNotFoundError, ZodmonValidationError, aggregate, checkUnindexedFields, collection, createAccumulatorBuilder, createClient, createExpressionBuilder, deleteMany, deleteOne, extractComparableOptions, extractDbName, extractFieldIndexes, find, findOne, findOneAndDelete, findOneAndUpdate, findOneOrThrow, generateIndexName, getIndexMetadata, getRefMetadata, index, insertMany, insertOne, isOid, objectId, oid, raw, serializeIndexKey, syncIndexes, toCompoundIndexSpec, toFieldIndexSpec, updateMany, updateOne };
|