Apollo GraphQL服务器:通过单独解析的字段进行过滤(或排序)。

问题描述 投票:5回答:1

我可能面临的设计限制是 Apollo GraphQL服务器 我想问一下是否有解决办法。

我的模式包含类型 Thing,具有场 flag. 我希望能够过滤 thingsflag但如果单独解决这个字段,似乎是不可能的。如果我想对这个字段进行排序,也会出现同样的问题。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 在所有异步字段都解决之后?我知道我可以调用 getFlagForThing(id) 里面 things resolver,但这不就是在重复我自己吗?解析背后的逻辑是 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;
    }
  },
};
graphql apollo-server
1个回答
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 不是原始人吗?好吧,如果你想通过它来过滤,那么你将有几个不同的选项。这些选项实际上取决于你是如何获取 "标志 "数据的。如果你能提供更多关于你的模式和数据模型的细节,我很乐意详细说明。

© www.soinside.com 2019 - 2024. All rights reserved.