3

我正在尝试查看是否有办法将平面列表转换为 rethinkdb 中的分层树。

鉴于此表:

nodes
------
-id
-name
-parent

我可以查询所有r.db('app').table('nodes')内容并获得一个平面列表:

[
  {name: "one", id: "1"}
  {name: "two", id: "2", parent: "1"}
  {name: "three", id: "3", parent: "2"}
]

但我真的很想要一个以层次结构返回数据的查询:

[
  {
    name: "one", 
    id: "1",
    children: [
      {
        name: "two", 
        id: "2", 
        children: [
          {name: "three", id: "3"}
        ]
      }
    ]
  }
]

这在 rethinkdb 中可能吗?Postgres 对此有WITH RECURSIVE查询。目前我正在应用程序层进行转换,但它变得越来越复杂——例如,要获取单个节点,我还必须获取所有节点,递归地添加其后代,然后只返回请求的节点。无论如何,如果可能的话,我很想在 rethinkdb 中找到一种方法来做到这一点。谢谢!

4

3 回答 3

1

不幸的是,在 RethinkDB 中没有简单的方法可以做到这一点。您对该模式的依恋程度如何?(如果答案是“不是很”,你需要在这张表上快速查询什么?)

于 2014-05-02T07:18:45.820 回答
1

我最近遇到了同样的问题。还想children为每个节点引入属性。但这并不好,因为每个新节点的创建/删除都会导致 2 次数据库写入操作。

所以,我想出的解决方案如下:

  1. 我使用group/ungroup聚合方法的 RethinkDB api
  2. 然后处理分组节点以输出最终树。

例如,获取您的输入数据,它在Node/Express后端看起来像这样:

r.db('app').table('nodes').group('parent').ungroup().run(dbConnection)
.then( groupedByParent => {
  // make a temp hashmap as grouped data from RethinkDB comes as Array 
  // of groups.
  const parentsMap = groupedByParent.reduce( (result, groupData) => {
    // each generated group has `group` prop which is the parent id in
    // our case and `reduction` prop which is the Array of all nodes
    // with this parent id
    const { group, reduction } = groupData

    // read prerequisites at the end of this post to better understand 
    // below contruction
    const parentId = group === null ? 'roots' : group

    result[parentId] = reduction
    return result
  }, {})

  // construct a final tree. parentMap will make it easier to get all 
  // children of particular node
  const tree = parentsMap.roots.map(function mapper(node) {
    // do nothing if this node doesn't have children
    const children = parentsMap[node.id]
    if (typeof children === 'undefined') return node;
    // else recursively iterate over children to grab all sub-children
    node.children = children.map(mapper)
    return node
  });
})

先决条件:要让它工作,所有节点都必须有parent属性(它不能丢失),所以如果节点没有父节点,它的parent属性将等于null

注意:ungroup在这里使用和准备最终树只是为了方便 - 使用标准 JavaScript 方法轻松操作分组数据,而不是使用 RethinkDB 的特殊控制结构。我想有可能只用 RethinkDB 的指令构建完整的树(例如,用fold方法)

如果您在节点表上创建索引,group那么 ing 也会更快。parent

于 2016-05-19T22:47:31.663 回答
0

If you want a finite set of nested children, you can use a join/subquery on the table itself

First create an index on parent

r.db('app').table('nodes').indexCreate("parent")

Then if you want just one level of children, you can do

r.db('app').table('nodes').merge(function(node) {
    return {
        r.db('app').table('nodes').getAll(node("id"), {index: "parent"}).coerceTo("ARRAY")
    }
})

If you need an arbitrary number of levels, that won't be possible, would it be because things are going to break if you have a circular reference.

于 2014-05-02T15:43:28.643 回答