Home > Software engineering >  What is the best approach to save a 4 level nested schema in mongoose NodeJs
What is the best approach to save a 4 level nested schema in mongoose NodeJs

Time:03-15

I have 4 level nested schema:

Framework has Domain referenced to it, Domain has control referenced to it, and Control has SubControl referenced to it.

Now I have been searching for a while and I keep getting confused.

First question: is it possible to post all the data from the framework it self? Second question: I have used referencing with ID approach, should I switch to using subDocuments?

Framework Schema:

const FrameworkSchema = new Schema({
  name: {
    type: String,
    trim: true
  },
  description: {
    type: String,
    trim: true
  },
  domain: [{
    domain: {type: Mongoose.Schema.Types.ObjectId, ref: 'Domain'}
  }],
  updated: Date,
  created: {
    type: Date,
    default: Date.now
  }
});

module.exports = Mongoose.model('Framework', FrameworkSchema);

Domain Schema:

const DomainSchema = new Schema({
   _id: {
     type: Schema.ObjectId,
     auto: true
   },
   domainNo: {
     type: String,
    trim: true
   },
   domainName: {
    type: String,
    trim: true
   },
  domainDescription: {
    type: String,
    trim: true
  },
  framework: {
    type: Mongoose.Schema.Types.ObjectId,
    ref: 'Framework'
  },
  control: [{
     control: {type: Mongoose.Schema.Types.ObjectId, ref: 'Control'}
  }],
  updated: Date,
  created: {
    type: Date,
    default: Date.now
  }
});

module.exports = Mongoose.model('Domain', DomainSchema);

My control Schema:

const ControlSchema = new Schema({
  _id: {
    type: Schema.ObjectId,
    auto: true
  },
  mainControl: {
    type: String
  },
    subControl: [{
        subControlNo: {type: Mongoose.Schema.Types.String, ref: 'SubControl'}
      }],
  controlDescription: {
    type: String,
    trim: true
  },
  updated: Date,
  created: {
    type: Date,
    default: Date.now
  }
});

module.exports = Mongoose.model('Control', ControlSchema);

My SubControl Schema

const SubControlSchema = new Schema({
    _id: {
      type: Schema.ObjectId,
      auto: true
    },
   subControlNo: {
     type: [String]
   },
  updated: Date,
  created: {
    type: Date,
    default: Date.now
  }
});

module.exports = Mongoose.model('SubControl', SubControlSchema);

Now I'm trying to post this nested documents from the framework api:

router.post(
  '/add',
  auth,
  role.checkRole(role.ROLES.Admin), async (req, res) => {
    try {

    const subControl = new SubControl({...req.body}); 
    const subControlDoc = await subControl.save();
    
    const control = new Control({...req.body});  // take the control data
    control.subControl.push(subControlDoc._id); // take the subControl and push the ID into the control
    const controlDoc = await control.save();

//make the subcontrol pushed into control
// make control pushed in domain

    const domain = new Domain({...req.body}); 
    domain.control.push(controlDoc._id); 
    const domainDoc = await domain.save();


    const framework = new Framework({...req.body}); 
    framework.domain.push(domainDoc._id); 
    const frameworkDoc = await framework.save(); //save the framework   domain's ID 



       res.status(200).json({
         success: true,
         message: `Framework has been added successfully!`,
         framework: frameworkDoc
       });
    } catch (error) {
      res.status(400).json({
        error
        // error: 'Your request could not be processed. Please try again.'
      });
    }
  }
);

Now I'm using push to push the data as an array, not sure if this the right approach, and Is it possible to post the all the data from the framework api?

Tried to post this from postman:

{
 "name": "ISO780001",
 "description": "frameworkDescription",
 "domain":
    [
    {
     "domainNo": "11",
     "domainName": "domainName00",
     "domainDescription": "domaindescu0",
     "control": [{
      "mainControl": "1-4",
      "subControl": [{
      "subControlNo": "1-4-1"
    },
    {
    "subControlNo": "1-4-2"
    }],
    "controlDescription": "controlDescriptionTest"
    },
    {
       
       "mainControl": "1-4",
      "subControl": [{
      "subControlNo": "1-4-1"
    },
    {
    "subControlNo": "1-4-2"
    }],
    "controlDescription": "controlDescriptionTest"
    }
]
  },
  {
     "domainNo": "1-2",
     "name": "domainName00",
     "description": "domaindescu0",
     "control": {
      "mainControl": "1-4",
      "subControl": [{
      "subControlNo": "1-4-1"
    },
    {
    "subControlNo": "1-4-2"
    }],
    "controlDescription": "controlDescriptionTest"
    }
  }
  ]
}

Only the id's of the domain, control, and subControl get saved in mongodb, is this the how it works can I post all the data from one model in this case the framework? or should I use embedded approach ?

CodePudding user response:

What I will do in scenario where i have alot of references (mongoose name it ref by the way, which allows you to populate).

Example of a frameWork schema with domain reference.

const frameworkSchema = mongoose.Schema({
    domains: [{type: mongoose.Schema.Types.ObjectId, ref: 'Domain'}],
})
const FrameworkModel = mongoose.model('Framework', frameworkSchema)

Domain above refers to a Domain model. We can create a domain model now.

const domainSchema = mongoose.Schema({
    _id: { type: mongoose.Schema.Types.ObjectId } //this is the default
})
const DomainModel = mongoose.model('Domain', domainSchema);

Example Usage - We want to get all the domain information related to a specific schema.

const results = FrameworkModel.findOne({ _id: 'some framework id'}).populate('domains').lean({ virtuals: true });

The results will be something like

{ 
    _id: 'some framework id',
    name: 'name of framework',
    domains: [
        {
           _id: 'id of domain 1',
           name: 'example.com'
        },
        {
           _id: 'id of domain 2',
           name: 'example2.com'
        }
    ]
}

You can also explore virtuals to see how you can maintain your framework, domains and other controls as separate collections, in order to easily reference to them. This is a better design than nesting multiple levels in a single document.

Unless where necessary, using separate collections has more benefits than using subdocuments. (easier to find documents and easier to update documents, and of course, more performant)

  • Related