【问题标题】:In GraphQL, how do I implement optional queries?在 GraphQL 中,如何实现可选查询?
【发布时间】:2018-07-24 04:19:44
【问题描述】:

编辑:由于似乎不清楚,我特意询问我应该在解析函数中为后端查询发出的数据库请求。

我正在实现 GraphQL 查询,但我无法准确理解在给定查询中应该进行多少次调用。例如,这是一个包含用户和用户可以加入的俱乐部的数据结构:

User {
  UserID
  Clubs
  OtherStuff
}

Club{
  ClubID
  ClubName
}

我可以对我的数据库进行以下调用:

  • 获取所有用户 ID
  • 获取 UserID 的信息
  • 获取用户的所有 ClubID
  • 获取 ClubID 的信息

我不明白的是,我是否应该在每次查询用户时都进行所有这些调用。如果某人只查询 UserID,那么检索其他所有内容似乎是一种巨大的浪费。 Clubs for User 应该是一个完全独立的 GraphQL 查询,Clubs 应该只返回 ClubID,还是有办法有效地允许 Clubs 字段中提供完整的 Club 信息?

编辑 2: 好的,这是我的代码。我已经评论了我不确定该怎么做的部分。

const QueryType = new GraphQLObjectType({
  name: 'Query',
  fields: {
    User: userQueryField,
    Club: clubQueryField
  }
});

const clubQueryField = {
  type: new GraphQLList(ClubType),
  args: {
    UserID: {
      description: 'Returns all clubs the user is a part of',
      type: GraphQLID
    }
  },
  resolve(root, {UserID}) {
    //.....
  }
};


const userQueryField = {
  type: new GraphQLList(UserType),
  args: {
    UserID: {
      description: 'If omitted, returns a list of all users. \
      Otherwise, returns the user with the provided ID',
      type: GraphQLID
    }
  },
  resolve(root, {UserID}) {
    if(UserID){
      return new Promise((resolve, reject) => {
        getUserInfo(UserID, function(response){

          //HERE: I have tried different things, like clubQueryField(UserID) and clubQueryField.resolve, but with no luck
          UserID.Clubs = clubQueryField
          resolve([response]);
        });
      });
    }
  }
};

编辑 3:用户类型定义。

const UserType = new GraphQLObjectType({
  name: 'User',
  fields: () => ({
    UserID: {
      type: GraphQLID
    },
    Clubs: {
      type: new GraphQLList(ClubType)
    }
  })
});

【问题讨论】:

  • 这一切都在解析器中完成,接口方面,您传递解析器获取信息所需的信息。是的,解析器应该进行所有这些调用。当然,您可以使用缓存来加快速度。根据您的问题,我可以告诉您将 GraphQL 查询与后端查询混淆了。
  • 我不认为我混淆了他们,但也许我的措辞不清楚。是什么让你觉得我在混淆他们?
  • 措辞。 ;-)
  • USERTYPE 是在哪里定义的?您应该将数据发送到 USERTYPE,然后在那里解析。我不明白你为什么在解析器中写解析器。您提到了type: new GraphQLList(UserType),但从未定义它。在 USERTYPE 模式中,您应该发回一组用户 ID。
  • @popctrl 很高兴它成功了!

标签: graphql graphql-js


【解决方案1】:

GraphQL API 按照类型和字段进行组织,我建议为用户类型和俱乐部类型创建单独的查询,如果有人只查询用户 ID,他们将使用用户查询。

查询用户:

query {
  users {
   id
  }
}

俱乐部查询:

query {
  club {
   clubID
   clubName
   userId
  }
}

如果有人试图查询用户/俱乐部,您可以将俱乐部类型添加到用户类型,如下所示:

query {
  users {
   id
   club {
    clubID
    clubName
   }
  }
}

在您的用户类型中,将有一个名为 club 的字段,该字段将是 club 类型,在解析器中,它将以 obj.userId 作为参数调用俱乐部查询,GraphQL 的美妙之处在于您让客户决定要获取哪些字段。

你可以看到一个嵌套查询的例子here

编辑:那么在您的情况下,您可以修改您的 userType 以包含用户所属的俱乐部,您不需要在 clubQueryField 中使用该条件,该条件将针对客户正在进行的查询,所以可以说你的用户类型是这样的:

用户类型:

export default new GraphQLObjectType({
  name: 'UserType',
  fields: {
    userId: {
      description: 'user id',
      type: GraphQLString
    },
    email: {
      description: 'user email',
      type: GraphQLString
    },
    clubs: {
      description: 'User clubs',
      type: new GraphQLList(ClubType),
      resolve: (obj, args, _) => {
        return getUserClubs(obj.userId);
      }
    },
  }
});

那么如果您的客户只需要用户,它将请求如下内容:

  query {
    User {
     userId
     email
     }
  }

如果客户需要用户和俱乐部,它会请求这样的内容:

query {
    User {
     userId
     email
     clubs {
        field1
        field2
       }
     }
  }

【讨论】:

  • 哇,这比预期的要容易得多。那么如何实现呢?我尝试了user.ClubIDs = clubQueryField 之类的方法,但我得到的只是“预期可迭代,但没有为字段 User.ClubIDs 找到一个。”
  • 不看你的代码很难知道,但这听起来像是一个类型问题,如果你想让你的字段返回一个数组,你的类型必须是 GraphQLList 的新实例,即new GraphQLList(club),而你必须确保您正在解析一个可迭代的集合,尝试调试您的响应并查看您在 db 调用中返回的内容,如果您可以提供一些更好的代码示例。
  • 查看我的编辑。这确实是一个列表,我不确定还有什么可以尝试的。
  • 您需要该条件的任何特殊原因?请检查我对答案的编辑
【解决方案2】:

GraphQL 具有延迟加载功能,可以处理查询中的其他字段。如果用户编写以下查询:

query{
   users{
    id
   }
}

它获取用户 ID,并且显然不寻找其他字段。不过,这绝对取决于您的解析器。如果你像这样编写解析器:users { resolve: body => get_user_id},它会从数据库中获取用户 ID。 希望这会有所帮助!

【讨论】:

  • 嗯,我想你误解了我 - 我知道 GraphQL 会延迟加载,我的问题与需要在解析函数中完成的数据库请求有关
  • 啊,这取决于您的数据库以及您用于连接 ot DB 并获取数据的接口。例如,我使用rest api,所以我在get_user_id() 函数中使用JavaScript 和fetch 库获取用户ID。
猜你喜欢
  • 2018-12-09
  • 2019-11-22
  • 2021-02-02
  • 2020-01-02
  • 2018-06-24
  • 2021-05-23
  • 2018-11-28
  • 2021-11-30
  • 2021-09-06
相关资源
最近更新 更多