Apollo GraphQL 服务器:按单独解析的字段过滤(或排序)
Posted
技术标签:
【中文标题】Apollo GraphQL 服务器:按单独解析的字段过滤(或排序)【英文标题】:Apollo GraphQL server: filter (or sort) by a field that is resolved separately 【发布时间】:2018-03-19 01:52:27 【问题描述】:我可能面临Apollo GraphQL server 的设计限制,我想问一下是否有解决方法。
我的架构包含类型 Thing
,该类型具有字段 flag
。我希望能够通过flag
的值过滤things
,但是如果单独解析该字段似乎是不可能的。如果我想对things
进行排序,也会出现同样的问题。这是一个例子:
type Thing
id: String!
flag Boolean!
type Query
things(onlyWhereFlagIsTrue: Boolean): [Thing!]!
const resolvers =
Thing:
flag: async (id) =>
const value = await getFlagForThing(id);
return value;
,
Query:
async things(obj, onlyWhereFlagIsTrue = false)
let result = await getThingsWithoutFlags();
if (onlyWhereFlagIsTrue)
// ↓ this does not work, because flag is still undefined
result = _.filter(result, ['flag', true]);
return result;
在解析所有异步字段后,有什么方法可以过滤things
?我知道我可以在things
解析器中调用getFlagForThing(id)
,但这不是重复我自己吗?解析flag
背后的逻辑可能比仅仅调用一个函数要复杂一些。
UPD:这是迄今为止我能找到的最佳解决方案。非常丑陋且难以扩展到其他领域:
const resolvers =
Thing:
flag: async (id, flag) =>
// need to check if flag has already been resolved
// to avoid calling getThingsWithoutFlags() twice
if (!_.isUndefined(flag))
return flag;
const value = await getFlagForThing(id);
return value;
,
Query:
async things(obj, onlyWhereFlagIsTrue = false)
let result = await getThingsWithoutFlags();
if (onlyWhereFlagIsTrue)
// asynchroniously resolving flags when needed
const promises = _.map(result, (id) =>
getFlagForThing(id)
);
const flags = await Promise.all(promises);
for (let i = 0; i < flags.length; i += 1)
result[i].flag = flags[i];
// ↓ this line works now
result = _.filter(result, ['flag', true]);
return result;
,
;
【问题讨论】:
【参考方案1】:我认为这里的问题实际上并不是 Apollo 服务器的限制,更多的是与您有一个带解析器的原始字段这一事实有关。通常,最好仅在字段要返回单独类型时才对字段使用解析器:
Thing
id: ID!
flag: Boolean!
otherThings: OtherThing
Query
things(onlyWhereFlag: Boolean): [Thing!]!
在本例中,为otherThings
单独设置一个解析器会很好,但如果一个字段是原始字段,那么我只需将该字段与 Thing 一起解析即可。
使用您的原始架构:
const filterByKeyValuePair = ([key, value]) => obj => obj[key] === value;
const resolvers =
Query:
async things(parent, onlyWhereFlag )
const things = await Promise.all(
(await getThings()).map(
thing =>
new Promise(async resolve =>
resolve(
...thing,
flag: await getFlagForThing(thing)
)
)
)
);
if (onlyWhereFlag)
return things.filter(filterByKeyValuePair(['flag', true]));
else
return things;
;
如果flag
不是原语怎么办?好吧,如果您想按它进行过滤,那么您将有几个不同的选择。这些选项实际上取决于您获取“标志”数据的方式。如果您能提供有关您的架构和数据模型的更多详细信息,我会很乐意详细说明。
【讨论】:
以上是关于Apollo GraphQL 服务器:按单独解析的字段过滤(或排序)的主要内容,如果未能解决你的问题,请参考以下文章
合并 Apollo 服务器的 GraphQL 解析器不使用 Object.assign()
如何使用 Apollo 分离 GraphQL 模式和解析器文件?
Graphql Apollo Federation - 基于实现服务解析计算域
Apollo GraphQL 服务器:在解析器中,从更高级别获取变量
我们如何从 apollo-server 模块传递 ApolloServer 中的数据源和合并的 graphql 模式和解析器?