Database design 数据库分层数据
我想看看是否有一种方法可以将平面列表转换为数据库中的层次树 鉴于此表:Database design 数据库分层数据,database-design,recursion,rethinkdb,Database Design,Recursion,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"} ] 但我确实希望查询以层次结构返回数据: [ {
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"}
]
}
]
}
]
这在DB中可能吗?Postgres对此有疑问。目前,我正在应用层进行转换,但它变得越来越复杂——例如,要获取单个节点,我还必须获取所有节点,递归地添加其子节点,然后仅返回请求的节点。不管怎么说,如果可能的话,我很想找到一种方法来解决这个问题。谢谢 不幸的是,在数据库中没有简单的方法可以做到这一点。您对该模式的依附程度如何?(如果答案是“不太”,那么需要在此表上快速执行哪些查询?如果需要一组嵌套子项,可以在表本身上使用联接/子查询 首先在父对象上创建索引
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 db的写入操作
因此,我提出的解决方案如下:
group
/ungroup
聚合方法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
});
})
先决条件:要使其正常工作,所有节点都必须具有父节点
属性(它不能丢失),因此如果节点没有父节点,则其父节点
属性将等于null
注意:我在这里使用解组
并准备最终的树只是为了方便-使用标准JavaScript方法而不是RejectDB的特殊控制结构轻松地操纵分组数据。我想只需要DB的指令就可以构建完整的树(例如,以某种方式使用fold
方法)
另外,如果您在nodes表上创建一个
父索引,则group
ing将更快。在RejectionDB中有这样做的方法,但它们非常复杂,不具有线程安全性,并且不是您希望在生产中使用的那种方法。如果有一个引人注目的用例,我们可以为此添加明确的支持。你能描述一下你为什么要找这样的功能吗?(请随时给我发电子邮件--slava@rethinkdb.com)谢谢你的回复,斯拉瓦。这种递归查询功能将有助于任何层次化数据用例,在这些用例中,您通常必须生成毛茸茸的应用程序逻辑或转向图形数据库。在我的例子中,我正在构建一个思维导图应用程序,其中每个节点可以有n个子节点。我绝对喜欢postgres的强大功能,但我更喜欢RejectDB的灵活模式,因为节点可以有不同的字段(描述、图片、检查表、标记等)。思想?更多关于递归查询的信息:啊,我明白了。也许图形数据库是更好的选择?我将考虑引入方便的递归功能,但这可能需要一段时间。太棒了,随时通知我!我也想要这个功能。目前,neo4j是我选择的数据库,但对于大型树来说,它无法扩展。我肯定会接受其他模式选项。也许在每个节点中都有一个ID的“子”数组会使这更容易一些。需要快速执行的查询包括:-获取一个节点及其所有子节点-更新一个节点可以将其作为一个包含嵌套文档的大型文档来完成,但这似乎并不理想。为此,这无疑是获取第一组子节点的好方法。现在,如果有一种方法可以像在postgres中那样递归地实现这一点。。。