1

I have an self referencing employee schema in mongoose.

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var Employee = new Schema({
  name: String,
  description: {
    type: String,
    default: 'No description'
  },
 manager: {
     type: Schema.Types.ObjectId,
     ref: 'Employee',
      default: null
  },
  reportee: [{
    type: Schema.Types.ObjectId,
    ref: 'Employee'
  }]

});

An employee can a manager & can have several reportee. If manager is null then the employee is treated as top level employee.

I need to created hierarchy based on this model. I am struggling to generate desired output.

So far I have tried to use popluate() & mongoose-deep-populate module but I am unable to get the desired output. I wonder its becuase I have a self referencing model. Or may be I am not using these two options properly.

This is what I have tried with deep-populate module. It seems to be populating reportee model but not repotree of reportee model. In short its only populating 1 level of records.

Employee.deepPopulate(employees, 'reportee.reportee.reportee.reportee.reportee', function (err, _employee) {
      employees.forEach(function (employee) {

      });
    });

Please suggest how can I retrive all the employee hierarchy ?

SharpCoder
  • 18,279
  • 43
  • 153
  • 249
  • So what do you want? If someone is the CEO then every reportee populates recursively in the entire company? Not sure of the uefulness of such a thing but just trying to clarify what you want. – Blakes Seven Jul 08 '15 at 09:36
  • Yes, thats what I want. I want to traverse till the end. As per the requirement, we will only have 300 employees at max. so ideally data should not be an issue !!! – SharpCoder Jul 08 '15 at 09:41
  • Not saying I won't look at it, but I would strongly advise against this course. If you are trying to build up some "TreeView" in a UI then a better approach is to make the request for the "children" as each "branch" is opened up, then add that data to the opened node. Or mongoose and/or any "plugin" can do is "burn through" lots of queries to fetch each employee and child nodes. For something so small you would be better off using XML than MongoDB or a relational engine. – Blakes Seven Jul 08 '15 at 09:57
  • What you are saying makes sense but we are already using MongoDB and users to wants to see all the data at once. I cannot say no until and unless the performance of getting all the data at once is really bad. – SharpCoder Jul 08 '15 at 10:04
  • Note: There is an open issue on the mongoose-deep-populate Github which basically suggests that this is impossible out of the box with that module. https://github.com/buunguyen/mongoose-deep-populate/issues/15 – SlashmanX Jul 08 '15 at 10:15
  • @SlashmanX: I just looked at this post: https://github.com/buunguyen/mongoose-deep-populate/issues/5 . This is also a self referencing model and if you specify `children.children.children.children`, it will load children upto 4 levels. – SharpCoder Jul 08 '15 at 10:26
  • In your schema definition you have a bottom-up hierarchy, which is not actually a hierarchy at all. An employee with no manager and no reportees (a CEO?) wouldn't have child references to populate. Neither populate not deepPopulate would work. You'll essentially have to find all (300) employees who reference the CEO then all (300?) employees who reference those (5x300?) managers ...and so on. For a CEO that's 300+(5*300)+(10*300)...=2x10^17 lookups!!! A simple hierarchy would have the manager and the reportee to have a list of employee references listen under them, not vice versa. – laggingreflex Jul 08 '15 at 11:27
  • @laggingreflex: I do not understand. In my case, every employee object will have a manager (can be null for CEO) & every employee object will also have its reportees. – SharpCoder Jul 08 '15 at 11:32
  • Suppose you want to create a hierarchy of a manager, and all the employees under than manager. You would do `Employee.find({manager:id})` which is you're looking up all 300 emps to find just the ones with a particular manager. Now you wanna go one level deeper, say one of the employees under that manager was a reportee, so you would `find({reportee:emp.id})` and so on and each time you'll end up looking up all 300 emps for every query. – laggingreflex Jul 08 '15 at 12:19

1 Answers1

1

To answer my own question, I am using mongoose-deep-populate library.

To use it we need to install the module:

npm install mongoose-deep-populate

//Register the plugin var deepPopulate = require('mongoose-deep-populate'); Employee.plugin(deepPopulate);

And then use this code:

Employee.deepPopulate(employees, 'reportee.reportee.reportee.reportee.reportee', function (err, _employee) {
      employees.forEach(function (employee) {

      });
    });

This will load 5 levels of reportees as we have mentioned reportee.reportee.reportee.reportee.reportee

SharpCoder
  • 18,279
  • 43
  • 153
  • 249