2

I got this function which recursively populates the children field of the Page model. However I found myself also having to do this for the modules field so I've spent the last 2 hours trying to rewrite this so that it has support for populating multiple fields, but without luck.

Here's the function:

exports.getSingle = (req, res, next) => {

  Page.findOne({_id: req.params.pageId})
    .exec((err, page) => {

    if (err || !page) {
      return next(err || 'No page with that _id');
    }

    const populate = (coll, id) => {

      return coll.findOne({_id: id})
        .then((page) => {

          if (!page.children || !page.children.length) {
            return page;
          }

          return Promise.all(page.children.map(childId => populate(coll, childId)))
            .then(children => Object.assign(page, {children}))
        });
    }

    populate(Page, page._id).then((page) => {

      res.json({
        error: null,
        data: page
      });
    });
  });
};

What I tried was adding a new parameter to the function called field and changing all children occurrences to field instead. While adding a new mapping in the Promise.all but I just end up with strange errors and non-populated data.

How can I achieve populating multiple fields?

EDIT:

Here's the Page model:

const PageSchema = new Schema({
  appConfigId: {type: mongoose.Schema.Types.ObjectId, ref: 'AppConfig'},
  parent: {type: mongoose.Schema.Types.ObjectId, ref: 'Page', default: null},
  children: [{type: mongoose.Schema.Types.ObjectId, ref: 'Page'}],
  modules: [{type: mongoose.Schema.Types.ObjectId, ref: 'Module'}],
  settings: {
    label: {type: String, default: '', maxlength: 100, required: true},
    url: {type: String, default: ''},
    data: {}
  },
  metadata: {
    type: {type: String, default: 'page', required: true}
  }
});

const Page = mongoose.model('Page', PageSchema);

And here's the Module model:

const ModuleSchema = new Schema({
  label: {type: String, required: true},
  modules: [{type: mongoose.Schema.Types.ObjectId, ref: 'Module'}],
  settings: {type: mongoose.Schema.Types.Mixed, default: {}},
  metadata: {
    type: {type: String, required: true},
    component: {type: String, required: true}
  }
});

const Module = mongoose.model('Module', ModuleSchema);
Chrillewoodz
  • 27,055
  • 21
  • 92
  • 175
  • Can you show us the schema design for `Page` model? – chridam Jan 25 '18 at 13:59
  • @chridam Updated with `Page` and `Module` models. – Chrillewoodz Jan 25 '18 at 14:02
  • Could it be as simple as `Page.findOne({_id: req.params.pageId}).populate('children modules parent appConfigId').exec((err, data) => {res.json({ error: null, data })});`? – chridam Jan 25 '18 at 14:08
  • @chridam Sadly no, that only populates one level deep. But since modules and pages can be nested indefinitely that won't work. – Chrillewoodz Jan 25 '18 at 14:29
  • Perhaps this could be of help https://stackoverflow.com/questions/18867628/mongoose-deep-population-populate-a-populated-field – chridam Jan 25 '18 at 14:52

0 Answers0