Strict Model
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
Promiseresolving to a newStrictDocumentwith updated types.
StrictQuery<Result, DocType>
An enhanced Mongoose Query type.
- populate(path): Returns a new
StrictQuerywith updatedResulttype. - exec(): Returns a
Promiseof the populated result.