MongoDB - 递归填充文档字段

时间:2018-01-21 14:15:49

标签: node.js mongodb recursion

我有Page

const PageSchema = new Schema({
  children: [{type: mongoose.Schema.Types.ObjectId, ref: 'Page'}]
});

正如您所看到的,每个Page都有一个children数组,该数组也是Page

现在我需要做的是获取所有" main"页面并填充他们的children数组,这很简单,除了我需要递归执行此操作,因为Page包含Page的数组。

MongoDB没有任何开箱即用的支持,它只支持2级深度人口。

这是我当前的查询(删除所有额外的内容以提高可读性),而不使用当前的.populate方法(因为它无论如何都不会起作用):

Page.find(query)
  .exec((err, pages) => {

    if (err) {
      return next(err);
    }

    res.json(pages);
  });

我看了一下这个问题,这个问题很相似,但并不完全符合我的要求:

mongoose recursive populate

似乎使用父级递归填充,它也只从1个文档开始,而不是我使用文档数组的方案,因为我使用的是.find而不是.findOne例如。

如何为此创建自己的深度递归填充函数?

旁注:

我知道由于性能的原因,我不建议使用我需要的解决方案,但我得出的结论是唯一解决方案对我有用。无论是在前端还是后端,我都需要进行递归获取,并且在后端正确执行会大大简化操作。此外,页面数量不会大到足以导致性能问题。

2 个答案:

答案 0 :(得分:0)

答案实际上是在前面问题的一个答案中撒谎,虽然有点模糊。这就是我最终得到的结果,效果非常好:

Page.find(query)
  .or({label: new RegExp(config.query, 'i')})
  .sort(config.sortBy)
  .limit(config.limit)
  .skip(config.offset)
  .exec((err, pages) => {

    if (err) {
      return next(err);
    }

    // takes a collection and a document id and returns this document fully nested with its children
    const populateChildren = (coll, id) => {

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

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

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

    Promise.all(pages.map((page) => {
      return populateChildren(Page, page._id);
    })).then((pages) => {

      res.json({
        error: null,
        data: pages,
        total: total,
        results: pages.length
      });
    });
  });

函数本身应该重构为一个可以在任何地方使用的utils函数,它也应该更通用一些,所以它也可以用于其他深度种群。

我希望将来可以帮助其他人:)

答案 1 :(得分:0)

您可以递归填充字段,如:

opt.apply_gradients (final_grads)

请注意,对于第一次填充,您不需要指定User.findOne({ name: 'Joe' }) .populate({ path: 'blogPosts', populate: { path: 'comments', model: 'comment', populate: { path: 'user', model: 'user' } } }) .then((user) => {}); 属性,因为它已在您的model架构中定义,但对于下一个嵌套群体,您需要执行此操作这一点。