Reputation: 5046
If I have two schemas, one which will be embedded in the other:
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
// Will embed this in the personSchema below
var addressSchema = new Schema({
street: String,
city: String,
state: {
type: String,
uppercase: true
},
zip: Number
});
var personSchema = new Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
emailAddress: {
type: String,
lowercase: true
},
phoneNumber: Number,
address: addressSchema
});
module.exports = mongoose.model("Person", personSchema);
I can't seem to get the uppercase: true
to work for embedded documents - no error is thrown, but it simply doesn't uppercase the state property. Or any kind of option like that.
I've been searching the Mongoose docs, but maybe I'm just not finding where it mentions that settings these kinds of additional options on subDocuments won't work.
Upvotes: 3
Views: 10295
Reputation: 5046
Not positive if this is the best way to do it or not, but I added a pre-save hook (per the suggestion of @nbro in the comments) and that seems to be working:
var addressSchema = new Schema({
street: String,
city: String,
state: {
type: String,
uppercase: true
},
zip: Number
});
addressSchema.pre("save", function (next) {
this.state = this.state.toUpperCase();
next();
});
var personSchema = new Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
emailAddress: {
type: String,
lowercase: true
},
phoneNumber: Number,
address: addressSchema
});
Update #1:
I seem to be able to find lots of cases of people embedding simple schemas without any additional validation (required: true
) or alteration (uppercase: true
) occurring. While the above solution does work, it seems kind of unnecessary. What I should probably be doing is just putting in the object literal to embed the info:
var personSchema = new Schema({
...
address: {
street: String,
city: String,
state: {
type: String,
uppercase: true
},
zip: Number
}
});
It seems like the only good reason to use a separate Schema is if you absolutely need the embedded data to have an _id
attribute and you don't need to add additional validation or alteration options to any of the properties. If you need an _id
, I'm guessing you should probably not be embedding the data, but saving it as a separate object and making a reference.
I'll keep updating this as I discover new information and best practices.
Update #2:
If you want to include validation to the embedded document, such as making the address
property required, you're going to have to do it separately, as outlined in this very good blog post about it.
Upvotes: 3
Reputation: 311865
Up until recently, Mongoose would throw an exception if you tried to directly embed one schema within another like you're doing. It looks like it's partially supported now, but apparently not for cases like this.
You can get this to work by using just the definition object from addressSchema
instead of the schema itself in the definition of the address
field of personSchema
.
var addressObject = {
street: String,
city: String,
state: {
type: String,
uppercase: true
},
zip: Number
};
var addressSchema = new Schema(addressObject);
var personSchema = new Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
emailAddress: {
type: String,
lowercase: true
},
phoneNumber: Number,
address: addressObject
});
Upvotes: 1