Mongoose.js - 使用实例方法的结果填充集合中每个项的属性

时间:2014-07-25 13:41:13

标签: javascript node.js mongodb mongoose

我对Mongoose.js感到烦恼 - 我有一个Category模式和一个Projects模式。每个类别可以包含任意数量的项目,每个项目都有typerelatedProjects数组,列出具有相同type的项目。 relatedProjects字段必须是随机的,并且限制为4 - 但我无法使用Mongoose执行此操作,而是使用lodash将relatedProjects的整个结果排在模式之外。

这是我正在使用的实例方法:

ProjectSchema.methods.findRelatedProjects = function(callback) {
  return this.model('Project')
    .where('type').equals(this.type) // find projects with the same type
    .where('_id').ne(this._id) // exclude this project from the result set
    .select('_id')
    .exec(callback);
};

这是我为单个项目获取relatedProjects的方法(我正在使用的承诺库是when.js):

router.get('/:id', function(req, res) {
  var data = {};
  when(Project.findOne({ _id: req.params.id }).exec())
  .then(function(project) {
    data.project = project;
    return node.call(data.project.findRelatedProjects.bind(data.project));
  })
  .then(function(relatedProjects) {
    var project = data.project.toObject();
    project.relatedProjects = _.first(_.shuffle(relatedProjects), 4);
    res.send(project);
  })
  .catch(function(error) {
    res.send(error);
  });
});

但是,当我在获取整个集合后尝试填充该字段时,无论是Categories还是Projects,我都会遇到麻烦。要么发回的结果都是空的(尽管console.log'结果会给我正确的数据),或者它会在没有设置relatedProjects字段的情况下返回。

以下是完全返回空的代码:

router.get('/content.json', function(req, res) {
  var data = {};
  when(Category.find({}).lean().exec())
  .then(function(categories) {
    data.categories = categories;
    return when.map(categories, function(category, i) {
      return when(Project.find({ category: category._id }).exec())
    })
    .then(function(projects) {
      return when.map(projects, function(project, j) {
        return node.call(project.findRelatedProjects.bind(project))
          .then(function(relatedProjects) {
            project.relatedProjects = relatedProjects;
            return project;
          })
      })
    });
  })
  .then(function(categories) {
    res.send({ categories: categories });
  })
  .catch(function(error) {
    res.send(error);
  });
});

值得注意的是when.map异步迭代,但我已经尝试定期循环以获得相同的结果。

此代码返回所有数据,但每个relatedProjects实例完全为空的事实除外。 (console.log(relatedprojects)给了我正确的数据):

router.get('/content.json', function(req, res) {
  var data = {};
  when(Category.find({}).populate('projects').lean().exec())
  .then(function(categories) {
    data.categories = categories;
    categories.forEach(function(category) {
      category.projects.forEach(function(project) {
        Project.findOne({ _id: project.id }, function(error, dbproject) {
          dbproject.findRelatedProjects(function(error, relatedprojects) {
            project.relatedProjects = relatedprojects;
          })
        });
      });
    });
    res.send({categories: categories});
  })
  .catch(function(error) {
    res.send(error);
  });
});

1 个答案:

答案 0 :(得分:0)

有一些问题。其中两个通过重构是一致的。第一个问题是用when.js包装一个mongoose承诺正在轻微搞砸了。第二个问题是在使用正确的数据填充文档之前调用了res.send。此代码修复了问题:

router.get('/content.json', function(req, res) {
  var data = { categories: [] };
  when.map(Category.find({}).exec(), function(category, i) {
    data.categories[i] = category;
    data.categories[i].projects = [];
    return when.map(Project.find({ category: category._id }).exec(), function(project, j) {
      data.categories[i].projects[j] = project.toObject();
      return node.call(project.findRelatedProjects.bind(project)).then(function(relatedProjects) {
        data.categories[i].projects[j].relatedProjects = _.first(_.shuffle(relatedProjects), 4);
      });
    });
  })
  .then(function() {
    res.send(data);
  })
  .catch(function(error) {
    res.send(error);
  });
});