RethinkDB分层数据

时间:2014-05-02 06:37:58

标签: database-design recursion rethinkdb

我试图查看是否有办法将平面列表转换为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中找到一种方法。谢谢!

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

如果你想要一个有限的嵌套子集,你可以在表本身上使用连接/子查询

首先在父

上创建一个索引
r.db('app').table('nodes').indexCreate("parent")

然后,如果你只想要一个级别的孩子,你可以做

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

如果您需要任意数量的级别,这是不可能的,那是因为如果您有循环引用,事情就会破裂。

答案 2 :(得分:0)

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

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

  1. 我使用RethinkDB api
  2. group / ungroup聚合方法
  3. 然后处理分组的节点以输出最终的树。
  4. 例如,在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索引,parent也会更快。