Schema Types
Let's explore the various schema types available for structuring your data effectively. Understanding these types is crucial for defining the shape and constraints of your data models. Each type serves a specific purpose and comes with its own set of modifiers that enhance its functionality. Whether you're working with strings, numbers, or booleans, this guide will provide you with the necessary insights to utilize these types to their fullest potential.
Primitives
String - string()
Defines a field that accepts string values. The string type is ideal for storing text data such as names, descriptions, emails, and any other textual information. It supports Unicode characters and can handle text of any length (within MongoDB's document size limits).
The string type has the following modifiers:
.lowercase()
: Transforms the value to lowercase before storing, useful for ensuring consistent data storage (e.g., email addresses)..uppercase()
: Transforms the value to uppercase before storing, commonly used for codes or identifiers.
Number - number()
Defines a field that accepts numeric values. The number type can store both integer and floating-point values, making it versatile for various numeric data such as quantities, measurements, prices, and calculations. It supports the full range of JavaScript's number type, including scientific notation.
Boolean - boolean()
Defines a field that accepts boolean values (true or false). Boolean fields are perfect for storing flags, toggles, or any binary state in your data model. They're commonly used for user preferences, feature flags, or status indicators.
Dates
Date - date()
Defines a field that accepts JavaScript Date objects. The date type stores timestamps with millisecond precision and handles timezone information. It's ideal for tracking events, timestamps, and temporal data where you need to perform date-based calculations or comparisons.
Date String - dateString()
Defines a field that accepts date strings in ISO format (YYYY-MM-DDTHH:mm:ss.sssZ). This type is useful when you need to work with date strings directly or when integrating with APIs that expect ISO format dates. It ensures consistent date string formatting across your application.
ObjectId
The objectId()
type represents MongoDB's unique identifier format. This type is commonly used for document IDs and establishing relationships between collections by referencing documents.
Arrays
The array()
type allows you to define fields that contain ordered lists of values, all of the same type. This is useful when you need to store multiple values of the same type in a single field.
Mixed
The mixed()
type represents a field that can accept any type of value. This type should be used sparingly as it bypasses TypeScript's type checking, making your schema less type-safe. Consider using it only when dealing with truly dynamic or unknown data structures.
Literals
The literal()
type allows you to define a schema with fixed possible values, similar to enums in TypeScript. This is useful for enforcing specific, predefined values for a field.
Objects
The object()
type allows you to define nested structures within your schema. This is essential for organizing related data into logical groups and creating complex data models. Objects can contain any other valid schema type as their properties.
Records
The record()
type enables you to create dynamic key-value pairs where all values must be of the same type. This is particularly useful when you need to store a collection of related items with arbitrary keys but consistent value types.
Tuples
The tuple()
type allows you to define arrays with a fixed number of elements where each element can have a different type. This is particularly useful when you need to represent data that always comes in a specific format, such as coordinates or key-value pairs with different types.
Tagged Union
The taggedUnion()
type provides a way to represent discriminated unions in your schema, where different variants of a type are distinguished by a tag field. This is ideal for modeling data that can take multiple forms but needs to be handled differently based on its type.
Union
The union()
type allows you to define fields that can accept multiple different types. Unlike tagged unions, regular unions don't require a discriminator field and are useful when you need to accept different types of values without explicitly tracking which type is being used.
Custom Type
The type()
function enables you to create your own custom schema types with specialized validation and transformation logic. This is invaluable when you need to enforce specific data formats or business rules that aren't covered by the built-in types.
Type Chaining
The pipe()
function is a powerful utility that allows you to chain multiple types together, applying their transformations and validations in sequence. This is particularly useful when you need to perform multiple transformations on a single field, such as converting a string input to a number.
General Modifiers
These modifiers can be applied to any field type to enhance their functionality and provide more flexibility in how data is handled:
-
.nullable()
: Allows the field to accept null values. This is useful when you need to explicitly represent the absence of a value, different from an undefined or omitted field. -
.default()
: Sets a default value if none is provided. You can specify a static value or a function that generates the default value. -
.optional()
: Makes the field optional, allowing it to be omitted when creating or updating documents. This is different from nullable() as an optional field doesn't need to be specified at all.