简体   繁体   English

MongoDB-递归填充文档字段

[英]MongoDB - Populate document field recursively

I've got a Page : 我有一个Page

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

As you can see each Page has an array of children which is also a Page . 正如你可以看到每个Page有一个数组children ,这也是一个Page

Now what I need to do is fetch all "main" pages and populate their children array, easy enough except for the fact that I need to do this recursively since a Page contains an array of Page s. 现在我需要做的是获取所有“主”页面,并填写自己的children阵列,很容易除了事实上,我需要因为要做到这一点递归Page包含数组Page秒。

MongoDB doesn't have any out of the box support for this, it only supports a 2 level deep population. MongoDB对此没有任何现成的支持,它仅支持2级深度填充。

Here's my current query (removed all extra stuff for readability) without using the current .populate method (since it's not gonna work anyway): 这是我当前的查询(为了可读性删除了所有多余的内容),而没有使用当前的.populate方法(因为无论如何它都无法工作):

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

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

    res.json(pages);
  });

I looked at this question which is similar but not exactly what I need: 我看了这个类似但不是我真正需要的问题:

mongoose recursive populate 猫鼬递归人口

That seems to use a parent to populate recursively and it also starts from just 1 document, rather than my scenario which uses an array of documents since I'm using .find and not .findOne for example. 这似乎使用父递归填充,它也开始从只1号文件,而不是我的情况,因为我使用它使用的文档的数组.find而不是.findOne的例子。

How can I create my own deep recursive populate function for this? 如何为此创建自己的深度递归填充函数?

Sidenote: 边注:

I am aware that the solution I need isn't recommended due to performance but I've come to the conclusion that it is the only solution that is going to work for me. 我知道由于性能原因不建议使用我需要的解决方案,但是我得出的结论是,这是唯一对我有用的解决方案。 I need to do recursive fetching regardless if it's in the frontend or backend, and doing it right in the backend will simplify things massively. 无论是在前端还是后端,我都需要进行递归提取,而在后端正确进行将大大简化工作。 Also the number of pages won't be big enough to cause performance issues. 同样,页面数将不足以导致性能问题。

The answer actually lied in one of the answers from the previous questions, although a bit vague. 答案实际上是先前问题的答案之一,尽管有点含糊。 Here's what I ended up with and it works really well: 这是我最终得到的结果,它确实运行良好:

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
      });
    });
  });

The function itself should be refactored into a utils function that can be used anywhere and also it should be a bit more general so it can be used for other deep populations as well. 该函数本身应重构为可以在任何地方使用的utils函数,并且它应该更通用一些,以便也可以用于其他深入人群。

I hope this helps someone else in the future :) 希望以后对其他人有帮助:)

You can recursively populate a field also like: 您可以递归填充字段,如下所示:

User.findOne({ name: 'Joe' })
   .populate({
      path: 'blogPosts',
      populate: {
         path: 'comments',
         model: 'comment',
         populate: {
            path: 'user',
            model: 'user'
         }
      }
   })
   .then((user) => {});

Please note that for first population, you don't need to specify model attribute, as it is already defined in your model 's schema, but for next nested populations, you need to do that. 请注意,对于第一个填充,您不需要指定model属性,因为它已经在model的架构中定义,但是对于下一个嵌套的填充,则需要这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM