v2.5.4
Playground
Api

Strict Model

Advanced, fluent type-safe population tracking.

Strict Model

The StrictModel API provides a powerful, type-safe wrapper around Mongoose models. It leverages Zod schemas to track the population state of your documents throughout the Mongoose query and document lifecycle.

Why use Strict Model?

Standard Mongoose population has limitations in TypeScript:

  • You often need to cast results to "populated" interfaces.
  • Population paths are not checked at compile-time.
  • Deep population quickly becomes a mess of complex types.

StrictModel solves this by using advanced TypeScript mapping to automatically infer the resulting type based on the .populate() calls you make.

Getting Started

To use StrictModel, wrap your Mongoose model initialization with toStrictModel.

import { z } from 'zod/v4';
import { toMongooseSchema, zRef, toStrictModel } from '@nullix/zod-mongoose';
import mongoose from 'mongoose';

const AuthorSchema = z.object({
  name: z.string(),
});

const PostSchema = z.object({
  title: z.string(),
  author: zRef('Author', AuthorSchema),
});

type Post = z.infer<typeof PostSchema>;

const mongooseSchema = toMongooseSchema(PostSchema);
const PostModel = toStrictModel<Post>('Post', mongooseSchema);

Features

1. Simple Population

When you populate a field, the returned document type is automatically updated.

const post = await PostModel.findOne({ title: 'Hello World' })
  .populate('author')
  .exec();

if (post && post.author) {
  // TypeScript knows post.author is populated!
  console.log(post.author.name); 
}

2. Deep Population (Dot Notation)

Supports deep population with full type safety for each level.

// Assuming Author has a 'user' field that is also a zRef
const post = await PostModel.findOne()
  .populate('author.user')
  .exec();

if (post) {
  // Both 'author' and 'author.user' are correctly typed
  console.log(post.author.user.username);
}

3. Multiple Paths

You can populate multiple paths using space-separated strings or by chaining calls.

const post = await PostModel.findOne()
  .populate('author mentions')
  .exec();

4. Object-Based Population

Recursive support for Mongoose's object-based population syntax.

const post = await PostModel.findOne().populate({
  path: 'author',
  populate: {
    path: 'user'
  }
}).exec();

API Reference

toStrictModel<T>(name, mongooseSchema)

Creates a StrictModel instance.

  • T: The Zod-inferred type for the document.
  • name: The model name.
  • mongooseSchema: The Mongoose schema instance.

StrictModel<RawModel, DocType>

A type that overrides standard Mongoose query methods to return StrictQuery instances.

StrictDocument<DocType>

An enhanced Mongoose Document type.

  • populate(path): Returns a Promise resolving to a new StrictDocument with updated types.

StrictQuery<Result, DocType>

An enhanced Mongoose Query type.

  • populate(path): Returns a new StrictQuery with updated Result type.
  • exec(): Returns a Promise of the populated result.