12

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.

Kucl Stha
  • 565
  • 1
  • 6
  • 20
  • 1
    Please see this post http://stackoverflow.com/questions/39914262/how-to-restrict-delete-in-mongodb-for-relationship-collection/39916241#39916241 – Clement Amarnath Oct 13 '16 at 11:43

2 Answers2

2

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.

0

You can use Promise.all method to perform all DB queries at once, like below:

Promise.all([
  OrderReceived.count({customer: req.params.id}),
  OrderSent.count({'customer.customer': req.params.id})
])
  .then(([orderReceivedCount, orderSendCount]) => {
    if (orderReceivedCount < 1 && orderSendCount<1) { 
      ...delete doc 
    }
   }).catch(error => ...handleError)
Jatin Parate
  • 528
  • 5
  • 9