Javascript 在Gatsby中查询子节点字段

Javascript 在Gatsby中查询子节点字段,javascript,graphql,gatsby,graphql-compose,Javascript,Graphql,Gatsby,Graphql Compose,我有下面的GraphQL模式,它定义了3种类型:一个CondaPackage,它有许多CondaVersion,它有许多CondaExecutable。我希望能够查询一个CondaVersion,并询问“您拥有多少个CondaExecutables,它们成功地完成了我的分析”。目前,我已经编写了一个succeedexecount和allExeCount,通过加载所有子项并手动计算成功的子项数量来解析此字段 exports.createSchemaCustomization=({actions:{

我有下面的GraphQL模式,它定义了3种类型:一个
CondaPackage
,它有许多
CondaVersion
,它有许多
CondaExecutable
。我希望能够查询一个
CondaVersion
,并询问“您拥有多少个
CondaExecutable
s,它们成功地完成了我的分析”。目前,我已经编写了一个
succeedexecount
allExeCount
,通过加载所有子项并手动计算成功的子项数量来解析此字段

exports.createSchemaCustomization=({actions:{createTypes},schema})=>{
创建类型([
schema.buildObjectType({
名称:“康达包装”,
字段:{
SucceedeExeCount:{
键入:“Int!”,
解析(源、参数、上下文){
//待办事项
}
},
allExeCount:{
键入:“Int!”,
解析(源、参数、上下文){
//待办事项
}
}
},
接口:[“节点”]
}),
schema.buildObjectType({
名称:“CondaVersion”,
字段:{
SucceedeExeCount:{
键入:“浮动!”,
解析(源、参数、上下文){
const children=context.nodeModel.getNodesByIds({
id:source.children,
类型:“CondaExecutable”
})
返回子项.reduce((acc,curr)=>acc+curr.fields.successed,0)
}
},
allExeCount:{
键入:“Int!”,
解析(源、参数、上下文){
返回source.childrence.length;
}
}
},
接口:[“节点”]
}),
schema.buildObjectType({
名称:“CondaExecutable”,
字段:{
成功:{
键入:“Boolean!”,
解析(源、参数、上下文、信息){
返回source.fields.successed | | false;
}
},
},
接口:[“节点”]
})
])
}
我的第一个问题是,这似乎非常低效。对于每个
CondaVersion
,我为其子项运行一个单独的查询,这是一个典型的N+1查询问题。有没有一种方法可以告诉Gatsby/GraphQL简单地“连接”两个表,就像我使用SQL来避免这种情况一样

我的第二个问题是,我现在需要从顶级类型:
CondaPackage
中计算后续子级的数量。我想问“你的孩子有多少个
CondaExecutable
s成功地完成了我的分析”。同样,在SQL中,这很容易,因为我只需加入这3种类型。然而,目前我唯一能做到这一点的方法是对每个孩子使用
getNodesByIds
,然后对每个孩子的孩子使用
n*m*o
运行时,这很可怕。我想运行一个GraphQL查询作为字段解析的一部分,该字段解析允许我从每个子级获取
succeedexecount
。然而,Gatsby的似乎返回节点而不包括派生字段,并且它不允许我选择其他字段来返回。如何访问Gatsby中节点的子节点的子节点上的字段?

编辑

下面是一位盖茨比维修人员对解决方案的回应:

盖茨比有一个内部机制,可以使用自定义解析程序按字段进行过滤/排序。我们称之为物化。[…]问题在于这不是一个公共API。这是一种可能有一天会改变的实现细节,这就是为什么它没有被记录在案的原因

原始答案

这里有一个小“秘密”(在撰写本文时,文档中没有提及):

当您使用
runQuery
时,盖茨比将尝试解析派生字段。。。但仅当该字段被传递到查询的选项(过滤器、排序、组、不同)时

例如,在
CondaVersion
中,您可以执行以下操作,而不是访问子节点并查找
字段

const succeededNodes=wait context.nodeModel.runQuery({
类型:“CondaExecutable”,
查询:{筛选器:{成功:{eq:true}}
})
CondaPackage
也一样。你可以试着这样做

const versionNodes=wait context.nodeModel.runQuery({
类型:“条件厌恶”,
查询:{}
})
返回versionNodes.reduce((acc,nodes)=>acc+node.SucceedeExeCount,0)//错误
您可能会发现
succeedexecount
未定义的

诀窍在于做到这一点:

const versionNodes=wait context.nodeModel.runQuery({
类型:“条件厌恶”,
-查询:{}
+查询:{filter:{succeedexecount:{gte:0}}}
})
这是违反直觉的,因为你会认为盖茨比只会解析一个类型上所有可解析的字段。相反,它只解析“已使用”的字段。为了解决这个问题,我们添加了一个过滤器,它应该什么都不做

但这还不是全部,
node.succeedexecount
仍然是
未定义的

解析的数据(
succeedexecount
)不是直接存储在节点本身,而是存储在
节点中。我们必须在那里访问它

const versionNodes=wait context.nodeModel.runQuery({
类型:“条件厌恶”,
查询:{filter:{succeedexecount:{gte:0}}}
})
返回versionNodes.reduce((acc,node)=>acc+node.\uuu gatsby\u已解析。succeededExeCount,0)
试试看&让我知道这是否有效


PS:我注意到您可能使用
createNodeField
(在
CondaExec
node.fields.successed
?)
createTypes
也可以在
exports.sourceNodes
中访问,因此您可以直接添加这个
successed
字段。

您的数据来自哪里?我很确定您可以直接使用SQL,没有任何东西强迫您通过
节点模型?没有SQL