如何在GraphQL中建模递归数据结构

rad*_*duw 14 graphql

我有一个树数据结构,我想通过GraphQL API返回.

结构不是特别大(小到足以在一次调用中返回它不成问题).

未设置结构的最大深度.

我已经将结构建模为:

type Tag{
    id: String!
    children: [Tag]
}
Run Code Online (Sandbox Code Playgroud)

当人们想要将标签带到任意深度时,就会出现问题.

要让所有孩子(例如)级别3,可以编写如下查询:

{ tags { id children { id children { id } } } }

有没有办法编写查询以将所有标记返回到任意深度?

如果不是建议的方法来建模如上所述的结构,如GraphQL API.

tle*_*nex 10

前一段时间,我想出了另一种解决方案,就像@WuDo建议的一样。

想法是使用ID引用树(每个有其父节点的子节点)并在ID上平整树,并标记树的根,然后在客户端再次递归构建树。

这样,您不必担心像@samcorcos的答案那样限制查询的深度。

模式:

type Query {
    tags: [Tag]
}

type Tag {
    id: ID!
    children: [ID]
    root: Boolean
}
Run Code Online (Sandbox Code Playgroud)

响应:

{ 
    "tags": [
        {"id": "1", "children": ["2"], "root": true}, 
        {"id": "2", "children": [], "root": false}
    ] 
}
Run Code Online (Sandbox Code Playgroud)

客户端树构建:

import find from 'lodash/find';
import isArray from 'lodash/isArray';

const rootTags = [...tags.map(obj => {...obj)}.filter(tag => tag.root === true)];
const mapChildren = childId => {
    const tag = find(tags, tag => tag.id === childId) || null;

    if (isArray(tag.children) && tag.children.length > 0) {
        tag.children = tag.children.map(mapChildren).filter(tag => tag !== null);
    }
}
const tagTree = rootTags.map(tag => {
    tag.children = tag.children.map(mapChildren).filter(tag => tag !== null);
    return tag;
});
Run Code Online (Sandbox Code Playgroud)

  • 顺便说一句,您也可以使用“parent: ID”来代替“root: Boolean”。这传达了相同的信息(parent = null 意味着 root = true),但允许客户端按他们认为合适的方式按父级和/或子级导航结构。 (3认同)