Skip to content

Commit 4786c93

Browse files
authored
Merge pull request #15721 from TechGenie-awake/docs-union-schema-type
docs: add documentation for Union Schema Type
2 parents ee6a377 + 2f7d2c1 commit 4786c93

File tree

1 file changed

+118
-0
lines changed

1 file changed

+118
-0
lines changed

docs/schematypes.md

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Check out [Mongoose's plugins search](http://plugins.mongoosejs.io) to find plug
4848
* [Buffer](#buffers)
4949
* [Boolean](#booleans)
5050
* [Mixed](#mixed)
51+
* [Union](#union)
5152
* [ObjectId](#objectids)
5253
* [Array](#arrays)
5354
* [Decimal128](api/mongoose.html#mongoose_Mongoose-Decimal128)
@@ -68,6 +69,7 @@ const schema = new Schema({
6869
updated: { type: Date, default: Date.now },
6970
age: { type: Number, min: 18, max: 65 },
7071
mixed: Schema.Types.Mixed,
72+
union: { type: Schema.Types.Union, of: [String, Number] },
7173
_someId: Schema.Types.ObjectId,
7274
decimal: Schema.Types.Decimal128,
7375
double: Schema.Types.Double,
@@ -720,6 +722,122 @@ The following inputs will result will all result in a [CastError](validation.htm
720722
* a decimal that must be rounded to be an integer
721723
* an input that represents a value outside the bounds of an 32-bit integer
722724

725+
### Union {#union}
726+
727+
The `Union` SchemaType allows a path to accept multiple types. Mongoose will attempt to cast the value to one of the specified types.
728+
729+
```javascript
730+
const schema = new Schema({
731+
value: {
732+
type: Schema.Types.Union,
733+
of: [String, Number]
734+
}
735+
});
736+
737+
const Model = mongoose.model('Model', schema);
738+
739+
// Both work - Mongoose accepts either type
740+
const doc1 = new Model({ value: 'hello' });
741+
const doc2 = new Model({ value: 42 });
742+
```
743+
744+
#### Casting Behavior
745+
746+
When you set a value on a Union path, Mongoose tries to cast it to each type in the `of` array in order. If the value matches one of the types exactly (using `===`), Mongoose uses that value. Otherwise, Mongoose uses the first type that successfully casts the value.
747+
748+
```javascript
749+
const schema = new Schema({
750+
flexibleField: {
751+
type: Schema.Types.Union,
752+
of: [Number, Date]
753+
}
754+
});
755+
756+
const Model = mongoose.model('Model', schema);
757+
758+
// Number type
759+
const doc1 = new Model({ flexibleField: 42 });
760+
doc1.flexibleField; // 42 (number)
761+
762+
// String '42' gets cast to Number (first type that succeeds)
763+
const doc2 = new Model({ flexibleField: '42' });
764+
doc2.flexibleField; // 42 (number)
765+
766+
// Date type
767+
const doc3 = new Model({ flexibleField: new Date('2025-06-01') });
768+
doc3.flexibleField; // Date object
769+
770+
// String date gets cast to Date
771+
const doc4 = new Model({ flexibleField: '2025-06-01' });
772+
doc4.flexibleField; // Date object
773+
```
774+
775+
#### Error Handling
776+
777+
If Mongoose cannot cast the value to any of the specified types, it throws the error from the last type in the union.
778+
779+
```javascript
780+
const schema = new Schema({
781+
value: {
782+
type: Schema.Types.Union,
783+
of: [Number, Boolean]
784+
}
785+
});
786+
787+
const Model = mongoose.model('Model', schema);
788+
789+
const doc = new Model({ value: 'not a number or boolean' });
790+
// Throws: Cast to Boolean failed for value "not a number or boolean"
791+
```
792+
793+
#### Union with Options
794+
795+
You can specify options for individual types in the union, such as `trim` for strings.
796+
797+
```javascript
798+
const schema = new Schema({
799+
value: {
800+
type: Schema.Types.Union,
801+
of: [
802+
Number,
803+
{ type: String, trim: true }
804+
]
805+
}
806+
});
807+
808+
const Model = mongoose.model('Model', schema);
809+
810+
const doc = new Model({ value: ' hello ' });
811+
doc.value; // 'hello' (trimmed)
812+
```
813+
814+
#### Queries and Updates
815+
816+
Union types work with queries and updates. Mongoose casts query filters and update operations according to the union types.
817+
818+
```javascript
819+
const schema = new Schema({
820+
value: {
821+
type: Schema.Types.Union,
822+
of: [Number, Date]
823+
}
824+
});
825+
826+
const Model = mongoose.model('Model', schema);
827+
828+
await Model.create({ value: 42 });
829+
830+
// Query with string - gets cast to number
831+
const doc = await Model.findOne({ value: '42' });
832+
doc.value; // 42
833+
834+
// Update
835+
await Model.findOneAndUpdate(
836+
{ value: 42 },
837+
{ value: new Date('2025-06-01') }
838+
);
839+
```
840+
723841
## Getters {#getters}
724842

725843
Getters are like virtuals for paths defined in your schema. For example,

0 commit comments

Comments
 (0)