如何使用handlebars输出嵌套的mongodb文档

huangapple go评论61阅读模式
英文:

How to use handlebars to output nested mongodb docs

问题

以下是翻译好的内容:

我有一个名为categories的MongoDB,结构如下:

{ (id), name, tree }

和数据:

{ (639...bc78), "ABC", null},
{ (63d...c891), "DEF", null},
{ (63f...718d), "yyy", ",ABC,"}

'yyy' 是 'ABC' 的子级。

我可以使用Handlebars输出所有数据

{{#each categories}}
  {{#if tree}}
    <tr><td> </td><td> </td><td>TREE:{{tree}}</td></tr>
  {{else}}
    <tr><td>{{_id}}</td><td>{{name}}</td></tr>
  {{/if}}
{{/each}}

这将输出:

639...bc78    ABC
63d...c891    DEF
63f...718d    yyy    TREE:ABC

我想要实现的是子文档的交错输出(即 'yyy' 在其父文档 'ABC' 之后输出):

639...bc78    ABC
              TREE: yyy
63d...c891    DEF

我对Express相当新,对express-handlebars非常新,找不到提供此功能的文档或建议。 任何想法/代码将不胜感激。

英文:

I have a mongodb called categories and structured as:

{ (id), name, tree }

and data:

{ (639...bc78), &quot;ABC&quot;, null},
{ (63d...c891), &quot;DEF&quot;, null},
{ (63f...718d), &quot;yyy&quot;, &quot;,ABC,&quot;}

'yyy' is a child of 'ABC'.

I can output ALL the data using handlebars

{{#each categories}}
  {{#if tree}}
    &lt;tr&gt;&lt;td&gt; &lt;/td&gt;&lt;td&gt; &lt;/td&gt;&lt;td&gt;TREE:{{tree}}&lt;/td&gt;&lt;/tr&gt;
  {{else}}
    &lt;tr&gt;&lt;td&gt;{{_id}}&lt;/td&gt;&lt;td&gt;{{name}}&lt;/td&gt;&lt;/tr&gt;
  {{/if}}
{{/each}}

This outputs:

639...bc78    ABC
63d...c891    DEF
63f...718d    yyy    TREE:ABC

What I would like to achieve is interleaved output of the child docs (i.e. 'yyy' outputs after its parent 'ABC'):

639...bc78    ABC
              TREE: yyy
63d...c891    DEF

I am fairly new to Express and very new to express-handlebars and cannot find any documentation or suggestions that would provide this functionality. Any ideas/code would be greatly appreciated.

答案1

得分: 2

在Handlebars模板中执行逻辑以获得所需的输出将是具有挑战性的。您需要编写一个自定义助手,这个助手需要进行大量循环,因为在外部类别循环的每次迭代中,它需要执行另一个类别循环来查找子类别。

更好的方法是在将数据传递给模板之前,将数据映射到不同的数据结构。在这个结构中,顶层类别对象将“拥有”它们自己的子类别数组。例如:

const categoriesByName = categories.reduce((acc, category) => {
  if (!category.tree) {
  	acc[category.name] = { ...category, children: [] };
  } else {
  	const parent = category.tree.replace(/,/g, '');
    
    if (acc[parent]) {
      acc[parent].children.push(category);
    } else {
      // 注意:我们假设子类别始终存在于其父类别之上。
      // 如果没有被索引的父类别名称,我们将丢失子类别。
      console.error(`No parent with name: ${name}`);
    }
  }
  
  return acc;
}, {});

这将产生如下结构:

{
  "ABC": {
    "_id": "639...bc78",
    "name": "ABC",
    "tree": null,
    "children": [
      {
        "_id": "63f...718d",
        "name": "yyy",
        "tree": ",ABC,"
      }
    ]
  },
  "DEF": {
    "_id": "63d...c891",
    "name": "DEF",
    "tree": null,
    "children": []
  }
}

注意:此结构不会超过两级 - 即,它不允许子类别拥有子类别。

有了这个结构,我们的模板需要遍历顶层类别,并为每个类别包含一个可能存在的子类别的内部循环:

{{#each categories}}
  <tr>
    <td>{{_id}}</td>
    <td>{{name}}</td>
  </tr>
  {{#each children}}
    <tr>
      <td></td>
      <td>TREE: {{name}}</td>
    </tr>
  {{/each}}
{{/each}}

这里是一个示例fiddle。

英文:

It will be challenging to get the output you want by performing the logic in the Handlebars template. You would need to write a custom helper and that helper would need to do a lot of looping because in each iteration of the outer category loop it would need to do another category loop to find the children.

The better approach would be to map your data to a different data structure before you pass it to your template. In this structure, the top-level category objects would "own" their own arrays of children. For example:

const categoriesByName = categories.reduce((acc, category) =&gt; {
  if (!category.tree) {
  	acc[category.name] = { ...category, children: [] };
  } else {
  	const parent = category.tree.replace(/,/g, &#39;&#39;);
    
    if (acc[parent]) {
      acc[parent].children.push(category);
    } else {
      // Note: We are assuming that children _always_ exist higher
      // in the array than their parents.
      // If no parent name has been indexed, we lose the child.
      console.error(`No parent with name: ${name}`);
    }
  }
  
  return acc;
}, {});

This will produce a structure like:

{
  &quot;ABC&quot;: {
    &quot;_id&quot;: &quot;639...bc78&quot;,
    &quot;name&quot;: &quot;ABC&quot;,
    &quot;tree&quot;: null,
    &quot;children&quot;: [
      {
        &quot;_id&quot;: &quot;63f...718d&quot;,
        &quot;name&quot;: &quot;yyy&quot;,
        &quot;tree&quot;: &quot;,ABC,&quot;
      }
    ]
  },
  &quot;DEF&quot;: {
    &quot;_id&quot;: &quot;63d...c891&quot;,
    &quot;name&quot;: &quot;DEF&quot;,
    &quot;tree&quot;: null,
    &quot;children&quot;: []
  }
}

Note: This structure does not get deeper than two-levels - ie., it doesn't allow children to have children.

With this structure, our template needs to iterate through the top-level categories and, for each, include an inner-loop for any children they might have:

{{#each categories}}
  &lt;tr&gt;
    &lt;td&gt;{{_id}}&lt;/td&gt;
    &lt;td&gt;{{name}}&lt;/td&gt;
 &lt;/tr&gt;
 {{#each children}}
   &lt;tr&gt;
     &lt;td&gt;&lt;/td&gt;
     &lt;td&gt;TREE: {{name}}&lt;/td&gt;
   &lt;/tr&gt;
 {{/each}}
{{/each}}

Here is an example fiddle.

huangapple
  • 本文由 发表于 2023年2月18日 23:31:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/75494378.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定