@prop
Typings:
function prop(
options?: BasePropOptions | ArrayPropOptions | MapPropOptions | PropOptionsForNumber | PropOptionsForString | VirtualOptions,
kind?: PropType
): PropertyDecorator
Parameters:
Name | Type | Description |
---|---|---|
options Required | BasePropOptions | The Option to set for the following property |
kind | PropType | Overwrite what Kind is used |
@prop
is used to mark properties to be in the Schema and also set Options of that property.
Any Property that does not have @prop
on it will not be in the Schema, because typegoose's current approach is that the keys for the schema get defined in @prop
, unlike class-transformer
's global-@Expose
and @Exclude
.
Single Options
Example:
class Cat {
@prop()
public name?: string;
}
class Cat2 {
@prop({ type: () => String }) // explicitly define the Type
public name?: string;
}
class Cat3 {
@prop({ type: () => String }, PropType) // explicitly define the "PropType"
public name?: string;
}
required
Accepts Type: boolean
Set this to true, if the property is required (best practice is public property!: any
, note the !
)
For more information see the mongoose documentation
Example:
class Something {
@prop({ required: true }) // this is now required in the schema
public firstName!: string;
@prop() // by default, a property is not required
public lastName?: string; // using the "?" marks the property as optional
}
index
Accepts Type: boolean
Create an Index for this Property. Should act like the @index
class decorator, but without options.
Example:
class IndexedClass {
@prop({ index: true })
public indexedField?: string;
}
unique
Accepts Type: boolean
Create an Index that sets this property to be unique.
Example:
class IndexedClass {
@prop({ unique: true }) // implicitly has "index: true"
public uniqueId?: string;
}
default
Accepts Type: any
Set a default, when no value is given at creation time.
Example:
class Defaulted {
@prop({ default: 'hello world' })
public upperCase?: string; // mark as optional, because it will be defaulted
}
You may also set the default
schema option to a function. Mongoose will execute that function and use the return value as the default.
Example:
class Defaulted {
@prop({ required: true })
firstName!: string
@prop({ required: true })
lastName!: string
@prop({
default: function (this: DocumentType<Defaulted>) {
return `${this.firstName} ${this.lastName}`
}
})
public fullName?: string; // mark as optional, because it will be defaulted
}
To have the this
keyword correctly typed, you have to pass a defined this parameter.
_id
Accepts Type: boolean
Set this to false
, if you want to turn off creating IDs for sub-documents.
Example:
class Nested {}
class Parent {
@prop({ _id: false })
public nest: Nested;
}
ref
Accepts Type: Class | string
Set which class to use for Reference (this cannot be inferred by the type).
Look here where Class
cannot be used
Example:
class Kitten {
@prop()
public name?: string;
}
class Cat {
// single examples
@prop({ ref: () => Kitten })
public kitten?: Ref<Kitten>;
// or
@prop({ ref: 'Kitten' })
public kitten?: Ref<Kitten>;
// array examples
@prop({ ref: () => Kitten })
public kittens?: Ref<Kitten>[];
// or
@prop({ ref: 'Kitten' })
public kittens?: Ref<Kitten>[];
}
The 'Nested'
(as string) form is useful to avoid unintuitive errors due to circular dependencies, such as Option "ref" for "${name}.${key}" is null/undefined! [E005]
.
refPath
Accepts Type: string
Set which path to look for which Class to use.
Example:
class Car {}
class Shop {}
// in another class
class Another {
@prop({ required: true, enum: 'Car' | 'Shop' })
public which!: string;
@prop({ refPath: 'which' })
public kind?: Ref<Car | Shop>;
}
validate
Accepts Type: object
OR RegExp
OR (value) => boolean
OR object[]
Required options of the object:
validator
:(value) => boolean
message
:String
, the message shows when the validator fails
Set a custom function for validation (must return a boolean).
Example: (For more Examples look at Mongoose's Documentation)
// "maxlength" already exists as an option, this just shows how to use validate
class Validated {
@prop({
validate: {
validator: (v) => {
return v.length <= 10;
},
message: 'value is over 10 characters long!'
}
})
public validated?: string;
}
alias
Accepts Type: string
Set an Alias for a property (best practice is to add type information for it).
-> For more information see the mongoose documentation
Example:
class Dummy {
@prop({ alias: 'helloWorld' })
public hello: string; // will be included in the DB
public helloWorld: string; // will NOT be included in the DB, just for type completion (gets passed as hello in the DB)
}
select
Accepts Type: boolean
Set it to false
, if you want to retrieve data without this property by default
-> Read more in Mongoose's official documentation
class Dummy {
@prop({ select: false })
public hello: string;
}
In order to retrieve a prop marked as select: false
, you must explicitly ask for it:
// find all in the collection and have the "hello" property selected
const dummies = await DummyModel.find().select('+hello').exec();
select()
accepts an array as well
select()
accepts a long string with space as a separator
get & set
Accepts Type: (input) => output
Set getters & setters for fields, it is not virtual.
Both get
& set
must be defined all the time, even when just wanting to use one.
If the PropType (Primitive / Array / Map) is different from what is got from the reflection, it requires explicit setting that it is different
Pre-process string to string:
class Dummy {
@prop({ set: (val: string) => val.toLowerCase(), get: (val: string) => val })
public hello: string;
}
Store string, runtime have string array (string array to string):
class Dummy {
// this value is a "string-array" during runtime and is stored in the database as a "primite-string"
@prop({ set: (val: string[]) => val.join(' '), get: (val: string) => val.split(' '), type: String }, PropType.NONE) // requires explicit setting of "PropType"
public fullName?: string[];
}
type
Accepts Type: any | any[] | () => (any | any[])
Overwrite the type generated for the design:type
reflection.
Example:
class Dummy {
// explicitly set type
@prop({ type: String })
public version1: string;
// supports deferred-function style
@prop({ type: () => String })
public version2: string;
}
Mongoose initializes arrays with []
instead of null
/ undefined
Example: Arrays (array item types can't be automatically inferred via reflection)
class Dummy {
@prop({ type: String })
public hello1: string[];
// supports wrapping type in nested arrays
// nested arrays are counted and will be used as option "dim"
@prop({ type: [[String]] })
public hello2: string[][];
}
(type: [[String]]
is equivalent to type: String, dim: 2
)
Since typegoose 12.11.0, type: [TYPE]
will also infer PropType.ARRAY
, unless manually specified.
Example: get as string[]
, save as string
class Dummy {
@prop({ set: (val: string[]) => val.join(' '), get: (val: string) => val.split(' '), type: String })
public hello: string[];
}
Example: Overwrite type for an enum.
enum SomeEnum {
One,
Two
}
class Dummy {
@prop({ enum: SomeEnum, type: Number })
public enumprop: SomeEnum;
}
Example: Overwrite the inferred type as a last resort.
class Dummy {
@prop({ type: mongoose.Schema.Types.Mixed }) // used for mongoose / how it is stored to the DB
public something: NewableFunction; // used for intellisense / TypeScript
}
enum
Accepts Type: TypescriptEnum | (string | number)[]
Only allow values from the enum (best practice is to use TypeScript's enum).
design:type
will be set to String
, if the enum is full of Strings, and Number
, if full of Numbers and Object
of the enum contains both.
Example for String-Enums:
enum Gender {
MALE = 'male',
FEMALE = 'female'
}
class Enumed {
@prop({ enum: Gender })
public gender?: Gender;
// typegoose enum also supports deferred function
@prop({ enum: () => Gender })
public gender?: Gender;
}
Example for Number-Enums:
(since mongoose 5.8 and typegoose 6.2)
enum Gender {
MALE, // equal to "= 0"
FEMALE // equal to "= 1"
}
class Enumed {
@prop({ enum: Gender })
public gender?: Gender;
// typegoose enum also supports deferred function
@prop({ enum: Gender })
public gender?: Gender;
}
Known-Issues:
- Babel doesn't set the type for enums correctly. They need to be set manually with the
type
option - If transpiling your code with
tsc --transpile-only
orts-node -- transpile-only
, then the--transpile-only
needs to be removed or the type needs to be set manually with thetype
option (see Known-Issues: Babel)
addNullToEnum
Accepts Type: boolean
Adds null
to the enum array.
This doesn't work if the value is required
Example:
enum SomeNumberEnum {
one = 1,
two = 2
}
class AddNullToEnum {
@prop({ enum: SomeNumberEnum, addNullToEnum: true })
public value?: SomeNumberEnum;
}
const AddNullToEnumModel = getModelForClass(AddNullToEnum);
AddNullToEnumModel.schema.path('value').options.enum === [1, 2, null]; // true
// this is necessary to avoid a validation error
new AddNullToEnumModel({ value: null } as AddNullToEnum);
discriminators
Accepts Type: () => [DiscriminatorObject | Class]
Use this function for embedded discriminators.
See Nested Discriminators for a guide on how to use nested Discriminators.
A Error is thrown when both this option and the model-option discriminators
are defined.
See Duplicate Option Definition [E032].
The discriminatorKey
(like in the example property type
) needs to be always set in a newly created document (via .create({ type: 'yourKey' })
, or .save()
)
There currently is no typegoose built-in way to get the models the path.discriminator
call would return, see typegoose/typegoose#744.
Example for [Class]
:
@modelOptions({
schemaOptions: {
discriminatorKey: 'type'
}
})
class Building {
@prop({ default: 100 })
public width: number;
@prop({ required: true })
public type: string;
}
class Garage extends Building {
@prop({ default: 10 })
public slotsForCars: number;
}
class SummerHouse extends Building {
@prop({ default: 100 })
public distanceToLake: number;
}
class Area {
@prop({ type: Building, discriminators: () => [Garage, SummerHouse] })
public buildings: Building[];
}
const AreaModel = getModelForClass(Area);
// then somewhere in an async function
const area = await AreaModel.create({});
area.buildings.push({ type: getName(SummerHouse), distanceToLake: 100 } as SummerHouse);
area.buildings.push({ type: getName(Garage), slotsForCars: 20 } as Garage);
await area.save();
Example for [DiscriminatorObject]
:
@modelOptions({
schemaOptions: {
discriminatorKey: 'type'
}
})
class Building {
@prop({ default: 100 })
public width: number;
@prop({ required: true })
public type: string;
}
class Garage extends Building {
@prop({ default: 10 })
public slotsForCars: number;
}
class SummerHouse extends Building {
@prop({ default: 100 })
public distanceToLake: number;
}
class Area {
@prop({
type: Building,
discriminators: () => [
{ type: Garage, value: 'G' },
{ type: SummerHouse, value: 'S' }
]
})
public buildings: Building[];
}
const AreaModel = getModelForClass(Area);
// then somewhere in an async function
const area = await AreaModel.create({});
area.buildings.push({ type: 'S', distanceToLake: 100 } as SummerHouse);
area.buildings.push({ type: 'G', slotsForCars: 20 } as Garage);
await area.save();
innerOptions
innerOptions
is used to override options at the "Type" level
Use this only when absolutely necessary and please open a new issue about it
This option can be used everywhere mapOptions
function is called (currently being PropType.ARRAY
and PropType.MAP
)
Example:
class Something {
@prop({ required: true })
public propy: string[];
}
// This would be mapped to
{
type: [{ type: String }],
required: true
}
// when using the override
class Something {
@prop({ innerOptions: { required: true } })
public propy: string[];
}
// This would be mapped to
{
type: [{ type: String, required: true }]
}
outerOptions
outerOptions
is used to override options at the "Array" level
Use this only when absolutely necessary and please open a new issue about it
This option can be used everywhere mapOptions
function is called (currently being PropType.ARRAY
and PropType.MAP
)
Example:
class Something {
@prop({ maxlength: 1 })
public propy: string[];
}
// This would be mapped to
{
type: [{ type: String, maxlength: 1 }]
}
// when using the override
class Something {
@prop({ outerOptions: { maxlength: 1 } })
public propy: string[];
}
// This would be mapped to
{
type: [{ type: String }],
maxlength: 1
}
allowMixed
allowMixed
is used to set a custom warnMixed
Severity for a specific Property.
Takes priority over class-wide allowMixed
.
See modelOptions#allowMixed
for all possible variants for the enum.
Example:
class Something {
@prop({ allowMixed: Severity.ERROR, type: () => mongoose.Schema.Types.Mixed })
public propy?: any;
}
buildSchema(Something); // would throw a "warnMixed" error
Array Options
Option type
must be provided, otherwise the array will result in Mixed
read typegoose issue #300 for more info
Example:
class Kitten {
@prop()
public name?: string;
}
class Cat {
@prop({ type: () => [Kitten] })
public kitten?: Kitten[]; // "[]" or "Array<any>" or "mongoose.Types.Array<any>" or "mongoose.Types.DocumentArray" is needed to be detected as an Array
}
class Cat2 {
@prop({ type: () => [Kitten] }, PropType.ARRAY) // explicitly define the "PropType"
public kitten?: Kitten[];
}
dim
dim
is used to set the Dimensions this array should have (for something like a matrix)
-> needs to be higher than 0
-> This Option is overridden by using type () => [Type]
Example:
class Something {
@prop({ dim: 3, type: String })
public propy: string[][][];
//or
@prop({ type: () => [[[String]]] })
public propy: string[][][];
}
// This would be mapped to
{
type: [[[{ type: String }]]]
}
The option dim
can be omitted when used with the () => [Type]
syntax (since 7.4.0
):
class ArrayInType {
@prop({ type: () => [[String]] }) // dim is 2
public propy: string[][];
@prop({ type: () => [String] }) // dim is 1
public propy: string[];
}
Map Options
Example:
class SomeMapClass1 {
@prop({ type: String })
public lookup?: Map<string, string>; // "Map<any, any>" or "mongoose.Types.Map<any>" is needed to be detected as a Map
}
class SomeMapClass2 {
@prop({ type: () => String }, PropType.MAP) // explicitly define the "PropType"
public lookup?: Map<string, string>;
}
// Extra Examples with different types
// Example: Primitive-Arrays
class SomeMapClass3 {
@prop({ type: () => [String] })
public lookup?: Map<string, string[]>;
}
// Example: SubDocuments
class Nested {
@prop()
public dummy?: string;
}
class SomeMapClass3 {
@prop({ type: () => Nested, _id: false })
public lookup?: Map<string, Nested>;
}
// Example: SubDocument-Arrays (since 8.1.1)
class Nested {
@prop()
public dummy?: string;
}
class SomeMapClass3 {
@prop({ type: () => [Nested], _id: false })
public lookup?: Map<string, Nested[]>;
}
type
can be Primitives, Primitive-Arrays, SubDocuments(Classes) and SubDocument(Class)-Arrays
String Transform options
lowercase
Accepts Type: boolean
Set this to true
, if the value should always be transformed to be lowercased.
Example:
class LowerCased {
@prop({ lowercase: true })
public lowerCase: string; // "HELLO" -> "hello"
}
uppercase
Accepts Type: boolean
Set this to true
, if the value should always be transformed to be UPPERCASE.
Example:
class UpperCased {
@prop({ uppercase: true })
public upperCase: string; // "hello" -> "HELLO"
}
trim
Accepts Type: boolean
Set this to true
, if the value should always be trimmed.
Example:
class Trimmed {
@prop({ trim: true })
public trim: string; // " Trim me " -> "Trim me"
}
String Validation options
maxlength
Accepts Type: number
Sets the maximum length the string can have.
Example:
class MaxLengthed {
@prop({ maxlength: 10 })
public maxlengthed?: string; // the string can only be 10 characters long
}
minlength
Accepts Type: number
Sets the minimum length the string can have (must be above 0).
Example:
class MinLengthed {
@prop({ minlength: 10 })
public minlengthed?: string; // the string must be at least 10 characters long
}
match
Accepts Type: RegExp
Sets a Regular Expression for the string must match.
Example:
class RegExpString {
@prop({ match: /^H/i })
public matched?: string;
}
Number Validation options
max
Accepts Type: number
Sets the maximum value the number property can have.
Example:
class Maxed {
@prop({ max: 10 })
public maxed?: number; // the value can be at most 10
}
min
Accepts Type: number
Sets the minimum value the number property can have.
Example:
class Mined {
@prop({ min: 0 })
public mined?: number; // the value must be at least 0
}
Virtual Populate Options
Options for Virtual Populate
ref
Required: yes, if using virtual populate
For Options and Typings, see normal ref
.
foreignField
Accepts Type: string | DynamicStringFunc<any>
Required: yes, if using virtual populate
Set the field to look at in the remote document and be compared with the field set by localField
.
localField
Accepts Type: string | DynamicStringFunc<any>
Required: yes, if using virtual populate
Set the field to look at in the local document and be compared with the field set by foreignField
.
justOne
Accepts Type: boolean
Conflicts with: count
Set whether the query should only return one document instead of a array of documents.
count
Accepts Type: boolean
Conflicts with: justOne
Set whether the query should return a count of found documents instead of the documents themself.
options
Accepts Type: mongoose.QueryOptions
Set custom options to be used in the query for virtual populate.
match
Accepts Type: object | (doc) => object
Set a custom matcher for virtual populate.
PropType
This is an Enum to represent what the prop should be, this is in most cases automatically set. It can be overridden in the second parameter of @prop
Full Enum:
enum PropType {
ARRAY,
MAP,
NONE // default for properties if no Map / Array is detected
}
For Examples, look at:
- Single Options -
NONE
- Array Options -
ARRAY
- Map Options -
MAP
Passthrough Class
It is not recommended to use this class, it should always be another class if nesting, like in the quick-start-guide is wanted
The Passthrough
class is, like the name implies, is to pass-through a schema definition directly, without "wrapping" it in a new Schema({})
explicitly.
Non-Direct
Using the Passthrough
class this way will be from mongoose 6.0 onward the same as doing another class (see Mongoose#7181).
Also see the FAQ Do all Classes get compiled to their own "mongoose.Schema"?
.
It should be noted that using this method no typegoose transformations or warnings will be applied to what is inside Passthrough.raw
(like type: () => Class
will not be translated, it will stay as-is).
There is also a option to set the Passthrough
class to direct
mode (with the second parameter), this will mean that absolutely no typegoose process is applied (everything has to be done manually), see Passthrough-Class#Direct.
Example for PropType.NONE
:
class PassthroughNoDirect {
@prop()
public normalProp?: string;
@prop({ type: () => new Passthrough({ somePath: String }) })
public child?: { somePath: string };
}
// would be equal to
new mongoose.Schema({
normalProp: {
type: String
},
child: {
type: {
somePath: String
}
}
})
Example for PropType.ARRAY
:
This was not working before mongoose 6.0.9, see issue #10750.
Using this way will throw a "Mixed" warning for property child
, because at the time where typegoose checks types is way before it being a proper Type.
class PassthroughNoDirect {
@prop({ type: () => new Passthrough({ somePath: String }) })
public child?: [{ somePath: string }]
}
// would be equal to
new mongoose.Schema({
child: {
type: [{
somePath: String
}]
}
})
Example for PropType.MAP
:
class PassthroughNoDirect {
@prop({ type: () => new Passthrough({ someProp: String }) })
public child?: Map<string, { someProp: string }>;
}
// would be equal to
new mongoose.Schema({
child: {
type: Map,
of: {
type: {
someProp: String
}
}
}
})
Direct
The option direct
(second parameter to Passthrough
, default false
), is used to set assigning the contents of raw
(first parameter to Passthrough
) directly, with no processing on the typegoose side or preceding type:
.
With the option direct
set to true
, no other option will be applied (even when defined) (like defining required
, will have no effect).
The most obvious one being that no type:
will be in-front of what Passthrough
holds.
Example for PropType.NONE
:
class PassthroughWithDirect {
@prop({ type: () => new Passthrough({ somePath: String }, true) })
public child?: { somePath: string; };
}
// would be equal to
new mongoose.Schema({
child: {
somePath: String
}
})
Example for PropType.ARRAY
:
class PassthroughWithDirect {
@prop({ type: () => new Passthrough([{ somePath: String }], true) })
public child?: [{ somePath: string; }];
}
// would be equal to
new mongoose.Schema({
child: [{ somePath: String }]
})
Example for PropType.MAP
:
class PassthroughWithDirect {
@prop({ type: () => new Passthrough({ type: Map, of: { somePath: String } }, true) })
public child?: Map<string, { somePath: string }>;
}
// would be equal to
new mongoose.Schema({
child: {
type: Map,
of: {
somePath: String
}
}
})