Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a better way to prevent document from deleting if a reference is present in another document in Mongodb via Mongoose?

I am creating a webapp using the following stack:

  • Node
  • Express
  • MongoDB
  • Mongoose

I have structured the app into a MVC structure.

There are Customer, OrderReceived and OrderSent schemas. OrderReceived and OrderSent schema references Customer schema. Abridge schema structures are following:

Customer

const mongoose = require('mongoose');

const customerSchema = mongoose.Schema({
  companyName: String,
  firstName: { type: String, required: true},
  lastName: { type: String, required: true}
});

module.exports = mongoose.model('Customer', customerSchema);

OrderReceived

const mongoose = require('mongoose');

const orderReceivedSchema = mongoose.Schema({
  receivedDate: { type: Date, required: true},
  customer: {type: mongoose.Schema.Types.ObjectId, ref: 'Customer', required: true}
});

module.exports = mongoose.model('OrderReceived', orderReceivedSchema);

OrderSent

const mongoose = require('mongoose');

const orderSentSchema = mongoose.Schema({
  sentDate: { type: Date, required: true},
  customer: {type: mongoose.Schema.Types.ObjectId, ref: 'Customer', required: true}
});

module.exports = mongoose.model('OrderSent', orderSentSchema);

When a Customer document is asked for delete, I want to check if it the document is referenced by either OrderReceived or OrderSent documents. And if there is a presence I want to prevent the deletion of the Customer document.

The solution I came up with is to do the check in the controller of Customer, as following:

CustomerController#destroy this handles the delete request:

destroy(req, res){
    OrderReceived.count({customer: req.params.id}, (error, orderLength)=>{
      if (error) res.send(error);
      if (orderLength<1){
        OrderSent.count({'customer.customer': req.params.id}, (error, orderLength)=>{
          if (error) res.send(error);
          if (orderLength<1){
            Customer.remove({_id: req.params.id}, error => {
              if (error) res.send(error);
              res.json({message: 'Customer successfully deleted.'});
            });
          } else {
            res.status(409).json({message: 'There are orders sent using the Customer. Datum could not be deleted'});
          }
        });
      } else {
        res.status(409).json({message: 'There are orders received using the Customer. Datum could not be deleted.'});
      }
    });
  }

Is there a better way to do this? I have other models that also depends upon the Customer document and this code is only going to get messier. Please help.

like image 930
Kucl Stha Avatar asked Oct 13 '16 07:10

Kucl Stha


1 Answers

When you are creating OrderReceived or OrderSent save reference of it in Customer too. So on this way before you delete it, you can simply check if they are empty or not. Your Customer schema would be like:

const customerSchema = mongoose.Schema({
    companyName: String,
    firstName: { type: String, required: true},
    lastName: { type: String, required: true},
    ordersSent: [{type: mongoose.Schema.Types.ObjectId, ref: 'OrderSent'}],
    ordersReceived: [{type: mongoose.Schema.Types.ObjectId, ref: 'OrderReceived'}],
});

and your delete function should contain something like:

Customer.findById(req.params.id)
    .then(customer => {
        if(customer.ordersSent.length== 0&& customer.ordersReceived.length== 0)
            return true
        //if there was more than 0
        return false
    }).then(result => {
        if(result)
            return Customer.findByIdAndRemove(req.params.id)
        res.status(409).json({message: 'There are orders received or sent using the Customer. Customer could not be deleted.'})
    }).then(customerDataJustInCase =>{
        res.status(200).json({message: 'Customer deleted.'})
    }).catch(err => {
        //your error handler
    })

or you can use it via try-catch.

like image 63
Ali Bagheri Avatar answered Oct 02 '22 22:10

Ali Bagheri