I am using a Schema as a Subdocument in Mongoose, but I am not able to validate it in its fields.
That's what I have
var SubdocumentSchema = new Schema({
foo: {
type: String,
trim: true,
required: true
},
bar: {
type: String,
trim: true,
required: true
}
});
var MainDocumentSchema = new Schema({
name: {
type: String,
trim: true,
required: true
},
children: {
type : [ SubdocumentSchema.schema ],
validate: arrayFieldsCannotBeBlankValidation
}
});
I want to be sure that every field of the subdocument is not empty.
I found out that this is not possible to validate an Array with standard methods, so I wrote my custom validation function.
By now I have to manually check that all the fields are correct and not empty, but it looks to me like a not really scalable solution, so I was wondering if there was some native method to trigger the Subdocument validation from the MainDocument one.
In the definition of children, it should be [SubdocumentSchema], not [SubdocumentSchema.schema]:
var MainDocumentSchema = new Schema({
name: {
type: String,
trim: true,
required: true
},
children: {
type : [ SubdocumentSchema ],
validate: arrayFieldsCannotBeBlankValidation
}
});
SubdocumentSchema.schema evaluates to undefined so in your current code Mongoose doesn't have the necessary type information to validate the elements of children.
Related
I want to generate two different objectIds in mongoose schema. One for departureLocation and one for arrivalLocation and want to reference it later.
I imported the object id from mongoose like this
let id = new mongoose.Types.ObjectId()
now I want to generate two different object ids like I said above
const routeSchema = new mongoose.Schema(
{
location: {
departureLocation: {
name: {
ref: "Location",
type: String,
required: true,
},
//want to create new object id here,
subLocation: [String],
_id: {
type: String,
},
},
arrivalLocation: {
name: {
ref: "Location",
type: String,
required: true,
},
//want to create new object id here,
subLocation: [String],
_id: {
type: String,
},
},
},
duration: {
type: Number,
required: true,
},
busId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Bus",
required: true,
},
date: {
type: String,
required: true,
},
},
{
timestamps: true,
}
);
MongoDB will automatically create _id for an object in a schema. You do not need to create one. In this schema, there will be 4 automatically generated _ids one for location, one for departureLocation, one for arrivalLocation, and one for the overall schema.
I am using mongoose in node.js. I have the following Schema.
const CustomerSchema = new mongoose.Schema({
...
email: {
type: String,
required: true,
lowercase: true,
trim: true
},
addresses: [
{
addressType: {
type: String,
enum: [ 'personal', 'shipping', 'billing' ]
},
street: {
type: String,
required: true,
trim: true
},
streetNumber: {
type: String,
trim: true
},
floor: {
type: String,
trim: true
},
apartament: {
type: String,
trim: true
},
cp: {
type: String,
required: true,
trim: true
},
district: {
type: String,
trim: true
},
city: {
type: mongoose.Schema.ObjectId,
ref: 'City',
required: true
}
}
]
});
I want to use "virtuals" to "add" a new field in every object in the array addresses?
How I can do this using virtuals? Is it possible?
I can achieve the same result using, but I would like to use virtuals.
const customerDB = await Customer.findById(idCustomer).lean()
customerDB.addresses = customerDB.addresses.map((address) => ({
...address,
addressDesc: mapTypeAddressDescription(address.addressType)
}));
Many Thanks!
As the name suggests virtuals are not added to the MongoDB documents. They are used for computed properties on documents.
Suppose you have a User model. Every user has an email, but you also want the email's domain. For example, the domain portion of 'test#gmail.com' is 'gmail.com'.
Below is one way to implement the domain property using a virtual. You define virtuals on a schema using the Schema#virtual() function.
const userSchema = mongoose.Schema({
email: String
});
// Create a virtual property `domain` that's computed from `email`.
userSchema.virtual('domain').get(function() {
return this.email.slice(this.email.indexOf('#') + 1);
});
const User = mongoose.model('User', userSchema);
let doc = await User.create({ email: 'test#gmail.com' });
// `domain` is now a property on User documents.
doc.domain; // 'gmail.com'
You should check the documentation for more details.
You can do something like this:
CustomerSchema.path('addresses').schema.virtual('fullAddr').get(function() {
return 'foo'
})
Also, it is useful to check this answer on stackoverflow if the above one doesn't work.
I'm trying to define the following mongoose model for a case. Strange I can not see a proper documentation about what I'm trying to do. In the end I want to have only 1 collection "Case"
which documents are nested object like this:
const CaseSchema = new Schema({
clientDataType: {
type: String,
required: true,
enum: [
'dataSchema1',
'dataSchema2',
],
},
clientData: {
type: "Either dataSchema1 or dataSchema2",
required: true,
},
caseDataType: {
type: String,
required: true,
enum: ['type1', 'type2', ...]
},
caseData: {
type: "One of 6 types of cases again they are schemas",
required: true,
}
}, { timestamps: true });
And here is mockup for dataSchema1 same goes for dataSchema2
const dataSchema1 = new Schema({
field1: {
type: String,
required: true,
},
fiedl2: {
type: String,
required: true,
},
field3: {
type: "One of subschemas of my choice",
required: true,
},
...
}, { timestamps: true });
Is mongoose capable of doing that or I must skip mongoose for this kind of case model. Basically at the end I wan't to submit this object and let mongoose validate it for me.
I have postSchema which references the tagsSchema.
var tagsSchem = new Schema({
name: {
type: String,
required: true
}
}, {
timestamps: true
});
// create a schema
var postsSchema = new Schema({
title: {
type: String,
required: true,
unique: true
},
mainImage: {
type: String
},
category: {
type: String,
required: true
},
body: {
type: String,
required: true
},
postedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
tags: [tagsSchem]
}, {
timestamps: true
});
One post can contain any no. of tags. So if a post has 3 tags then I want to get all the posts with those 3 tags without querying it multiple times. Is it possible?
When you perform find, you can use the $in option to find values that are in your array. For example:
posts.find({tags:{$in:{["tag1","tag2","tag3"]}}, function(err,data) {
... //Your code here
}
This will take all the posts that contains one of the three tags. It's important you have to pass an array in the $in option. This should work.
Given the goal of having a JSON object that can be passed to a consumer where the json object contains some variation of:
{
_id: 1
name: "my_name",
type: "my_type",
my_particulars: {
value: 1,
author: "some author"
}
}
such that the "type" value is locked into the schema/model is there an established pattern for satisfying this requirement?
It seems to me that the best options is some form of:
var WidgetSchema = new Schema({
//Name
name: {type: String, required: true, unique: true},
type: {type: String, required: true, default: "widget"},
title: {type: String, required: true },
description: { type: String, required: true },
//Status 1: Not Live
//Status 2: Live
status: {type: Number, required: true, default: 1}
});
WidgetSchema.virtual('type').set(
function () {
return false;
});
Instead of actually storing the type you can add it as a virtual property which is returned with the JSON. Something like:
WidgetSchema.virtual('type').get(function () {
return 'widget';
});
With this defined, you can instruct mongoose to include virtuals in the toObject/toJSON output by passing the virtuals option.
// either directly to the method
instanceOfWidget.toJSON({virtuals: true});
// or as a default by setting the option on the schema
WidgetSchema.set('toObject', {virtuals: true});