Pick Avana
Pick Avana

Reputation: 132

Mongoose Schema Custom Async Validator throwing TypeError - callback is not a function error

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

Answers (2)

Clementine
Clementine

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

Pick Avana
Pick Avana

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

Related Questions