我有一个树数据结构,我想通过GraphQL API返回。
结构不是特别大(足够小,在一次通话中不会出现问题)。
未设置结构的最大深度。
我已将结构建模为:
type Tag{
id: String!
children: [Tag]
}
当想要将标签带到任意深度时,会出现问题。
要让所有孩子(例如)等级3,可以编写如下的查询:
{
tags {
id
children {
id
children {
id
}
}
}
}
有没有办法编写查询以将所有标记返回到任意深度?
如果不是建议在GraphQL API中为上述结构建模的方法是什么。
答案 0 :(得分:7)
前一段时间,我想出了另一种解决方案,与@WuDo建议的方法相同。
想法是使用ID引用树(每个有其父级的子级)并在ID上平整树,并标记树的根,然后在客户端再次递归地构建树。
这样,您不必担心像@samcorcos的答案那样限制查询的深度。
模式:
type Query {
tags: [Tag]
}
type Tag {
id: ID!
children: [ID]
root: Boolean
}
响应:
{
"tags": [
{"id": "1", "children": ["2"], "root": true},
{"id": "2", "children": [], "root": false}
]
}
客户端树构建:
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;
});
答案 1 :(得分:0)
最好的办法是传递参数并在解析器中使用该参数。您的语法将根据您采用的模式而有所不同,但这是它的要点。
/*
Add an argument to your query:
query {
tags(depth: 3) {
id
children
}
}
*/
export default {
Query: {
tags: async (obj, { depth, }, context) => {
// depending on how you're getting tags, run the function
// that gets you a list of tags
const tags = await getTags(obj, { depth, }, context)
// depending on which ORM you're using, join
// `depth` number of times here on `tags.children`
return tags
}
}
}

显然,每当你以这种方式递归查询时,你都会冒着数据库爆炸的风险,但只要你知道自己在做什么,就应该没问题。