skip to Main Content

I want to let the front end know if there is a validation issue such as a duplicate submission ID. I have ready many stack posts already and tried the various solutions in this code…

in short none of the catch methods are catching an error. It as though mongo or mongoose is throwing it before my code gets a look in 🙁

here is my code

exports.createFinishedJob = async (req, res) => {

    try {
        console.log('createFinishedJob req.body', req.body);
        const finishedjob = new FinishedJob();
        if (req.body.jobSubmissionId) { finishedjob.jobSubmissionId = req.body.jobSubmissionId };
        if (req.body.customerId) { finishedjob.customerId = new ObjectId(req.body.customerId) };
        finishedjob.finishedjob = req.body.finishedjob;
        if (req.body.other) { finishedjob.other = req.body.other };
        console.log('createFinishedJob', finishedjob);

        let error;
        try {
            await finishedjob.save()
                .catch(err => console.log("HALLO err", err));
            // if (res && doc) {
            //     return res.json(doc);
            // } else {
            //     return doc
            // }
        } catch (err) {
            error = err;
            console.log("createFinishedJob error", error)
        }
    } catch (err) {
        console.error("Something went wrong")
        console.error(err)

    }
};

here is the error:-

(node:85241) UnhandledPromiseRejectionWarning: MongoServerError: E11000 duplicate key error collection: Genaich.processingjobs index: jobSubmissionId_1 dup key: { jobSubmissionId: "1006006" }
    at /Users/urfx/phos-code/genaich/node_modules/mongodb/lib/operations/insert.js:50:33
    at /Users/urfx/phos-code/genaich/node_modules/mongodb/lib/operations/command.js:84:64
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
(node:85241) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)

here is the model

const  mongoose  = require("mongoose");
const  Schema  =  mongoose.Schema;
const {ObjectId} = mongoose.Schema;
const SchemaTypes = mongoose.Schema.Types;
const  finishedjobSchema  =  new Schema(
    {
        customerId: { 
            type: ObjectId,
            ref: "User",
            required: false 
        },
        jobSubmissionId:{
            type: String, // if we don't get one from the customer use payment / order number
            unique: true,
            index: true
        },
        trashed: {
            type: Boolean
        },
        finishedjob: {
            type: Object
        },
        other: {
            type: SchemaTypes.Mixed // to start the ball rolling 
        }

    },
    { timestamps: true });

let  FinishedJob  =  mongoose.model("FinishedJob", finishedjobSchema);
module.exports  =  FinishedJob;

2

Answers


  1. Chosen as BEST ANSWER

    Many thanks @jQueeny

    Your first suggestion using "create" does what I need with a slight tweak I should have mentioned I also wanted to return the successful new doc too. I couldn't put all this in the comments.

    /**
     * THANKS @jQueeny for this working solution to handling 11000 with a catch
     * using create instead of save... seems I had the clue in my method name to 
     * start with
     * @param {*} req 
     * @param {*} res 
     * @returns duplicate error if the submissionId already exists otherwise returns the new "finished" document
     */
    exports.createFinishedJob = async (req, res) => {
       try {
            // If this fails for any reason it will throw to the catch block
            const finishedjob = await FinishedJob.create({
                jobSubmissionId: req.body.jobSubmissionId,
                customerId: req.body.customerId,
                finishedjob: req.body.finishedjob,
                other: req.body.other
            });
            // This will only return if the document was created successfully
            if (res && finishedjob) {
                console.log({"success":finishedjob});
                return res.status(200).json({"success":finishedjob});
            } else {
                return finishedjob
            }
        } catch (err) {
            console.error(err);
            // Check for the E11000 duplicate key error
            if(err.code === 11000){
                return res.status(400).json({
                    message: err.message
                });
            }else{
                return res.status(500).json({
                    message: 'Error on server'
                });
            }
        }
    };
    

  2. Option one would be to use the Model.create() method and just catch any errors that it throws. The Model.create() is just like a const doc = new Model(); + doc.save() all in one method. Use like so:

    exports.createFinishedJob = async (req, res) => {
       try {
            // If this fails for any reason it will throw to the catch block
            const finishedjob = await FinishedJob.create({
                jobSubmissionId: req.body.jobSubmissionId,
                customerId: req.body.customerId,
                finishedjob: req.body.finishedjob,
                other: req.body.other
            });
            // This will only return if the document was created successfully
            return res.status(200).json({
                message: 'Job Created'
            });
        } catch (err) {
            console.error(err);
            // Check for the E11000 duplicate key error
            if(err.code === 11000){
                return res.status(400).json({
                    message: err.message
                });
            }else{
                return res.status(500).json({
                    message: 'Error on server'
                });
            }
        }
    };
    

    Option two would be to quickly check if a Finishedjob with jobSubmissionId already exists and return the error message early. However, if there is no match then you still need to create the new document again which means two calls to the database so if you are handling thousands of new requests to that route per minute then obviously less efficient. Use like so:

    exports.createFinishedJob = async (req, res) => {
        try {
            const existingFinishedjob = await FinishedJob.findOne({
               jobSubmissionId: req.body.jobSubmissionId
            });
            if (existingFinishedjob){
                return res.status(400).json({
                    message: 'Already exists'
                });
            }
            const finishedjob = await FinishedJob.create({
                jobSubmissionId: req.body.jobSubmissionId,
                customerId: req.body.customerId,
                finishedjob: req.body.finishedjob,
                other: req.body.other
            });
            return res.status(200).json({
                message: 'Job Created'
            });
        } catch (err) {
            console.error(err);
            return res.status(500).json({
                message: 'Error on server'
            });
        }
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search