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

Ale*_*aev 5 graphql apollo-server

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

我的架构包含类型Thing,具有字段flag。我希望能够things按 的值进行过滤flag,但如果单独解析此字段似乎是不可能的。如果我想对things. 下面是一个例子:

  type Thing {
    id: String!
    flag Boolean!
  }

  type Query {
    things(onlyWhereFlagIsTrue: Boolean): [Thing!]!
  }
Run Code Online (Sandbox Code Playgroud)
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;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

things解析所有异步字段后,是否有任何过滤方法?我知道我可以调用getFlagForThing(id)内部things解析器,但这不会只是重复自己吗?解析背后的逻辑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;
    }
  },
};
Run Code Online (Sandbox Code Playgroud)

小智 1

我认为这里的问题实际上并不是 Apollo 服务器的限制,更多的是与您有一个带有解析器的原始字段有关。一般来说,最好仅当字段要返回单独的类型时才对字段使用解析器:

Thing {
    id: ID!
    flag: Boolean!
    otherThings: OtherThing
}

Query {
    things(onlyWhereFlag: Boolean): [Thing!]!
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,为 提供单独的解析器就可以了otherThings,但如果某个字段是原语,那么我只需将该字段与 Thing 一起解析即可。
使用您的原始架构:

Thing {
    id: ID!
    flag: Boolean!
    otherThings: OtherThing
}

Query {
    things(onlyWhereFlag: Boolean): [Thing!]!
}
Run Code Online (Sandbox Code Playgroud)

如果flag不是原始人怎么办?好吧,如果您想通过它进行过滤,那么您将有几个不同的选择。这些选项实际上取决于您如何获取“标志”数据。如果您可以提供有关架构和数据模型的更多详细信息,我将很乐意详细说明。