Reputation: 132
Trying to make a custom async schema validator in mongoose, to check that "tags" for a course being created contains at least one item. (Using SetTimeout() to simulate async). The part of the Schema for tags is :
tags: {
type: Array,
validate: {
isAsync: true,
validator: function (v, cb) {
setTimeout(() => {
//do some async work
const result = v && v.length > 0;
cb(result);
}, 3000);
},
message: "A course should have at least one tag!",
},
},
The code for creating a course is:
async function createCourse() {
const course = new Course({
name: "Node.js Course",
author: "Anon",
category: "web",
tags: [],
isPublished: true,
price: 13,
});
try {
const result = await course.save();
cl("createCourse result", result);
} catch (ex) {
cl("createCourse validate error", ex.message);
}
}
createCourse();
I have an empty array for tags and expected the caught error "A course should have at least one tag". Instead I am getting TypeError: cb is not a function for cb(result), the callback result? Even if I have an item in the tags array it still gives the callback error and in fact it displays the createCourse result BEFORE the schema async completes and then throws the error when it does complete! (If I dont use the async validator but just a plain validator then it works fine).
Upvotes: 0
Views: 377
Reputation: 11
tags: {
type: Array,
validate: {
validator: function(v) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(v && v.length > 0);
}, 3000);
})
},
message: 'A course should have at least one tag.'
}
},
Upvotes: 1
Reputation: 132
After trial and error, I came up with the solution below. No changes needed to createCourse(), just to the Schema tags section and added a delay function.
tags: {
type: Array,
validate: {
//isAsync: true,
validator: async function (v) {
await delay(3);
const result = v && v.length > 0;
return result;
},
message: "A Document should have at least one tag!",
},
},
And this calls a delay function, used to simulate a "real" async situation where this data may be being saved to a remote server.
const delay = (n) => {
return new Promise(function (resolve) {
setTimeout(resolve, n * 1000);
});
};
Upvotes: 0