在GraphQL中,如何通过客户端查询控制数据库查询?

时间:2019-03-05 09:42:09

标签: graphql graphql-js

这些天我学会了使用GraphQL。我认为,要构建查询,我需要构建三个部分:

  1. 架构
type User{
  id String
  name String
  cars [Car!]!
}
type Car{
  id String
}
type Query{
  user(id: String): User
}
  1. 数据库查询功能
{
  user: async function ({id}) {
    const user = await DB.user.findOne({id});
    const userCars = await DB.car.find({userId: id});
    user.cars = userCars;
    return cars;
  }
}
  1. 客户查询
{
  user (id: "1") {
    name
    cars {
      id
    }
  }
}

该查询返回用户名和他的汽车。数据库查询功能始终查询汽车。

但是有时候我只需要用户信息:

{
  user (id: "1") {
    name
  }
}

我不想查询汽车,因此希望使我的数据库查询功能可以自动选择是否查询汽车。

我该怎么做?

3 个答案:

答案 0 :(得分:1)

GraphQL.js将支持对象属性或解析器功能的方法;在Object Types的页面中对此进行了讨论。

一种解决方法是将匿名函数直接插入返回的对象中:

{
  user: async function ({id}) {
    const user = await DB.user.findOne({id});
    user.cars = () => DB.car.find({userId: id});
    return cars;
  }
}

另一种方法是使用提供id属性和(异步,惰性)cars方法的类创建包装对象; GraphQL.js documentation中提供了一些示例。这种方法往往适用于大多数语言的大多数GraphQL实现。

答案 1 :(得分:0)

我认为您正在研究从GraphQL查询到数据库查询的自动创建/映射。

每个查询都是特定于数据库/项目的,因此您应该创建此映射。您可以使用graphql-fields软件包轻松地做到这一点。

包装中有复制粘贴的“为什么”部分:

  

基础REST api可能仅基于查询参数返回字段。

{
  user {
    profile {
      firstName
    },
    id
  }
}
     

应请求/api/user?fields=profile,id

     

同时

{
  user {
    email
  }
}
     

应请求/api/user?fields=email   像这样实现您的解决方法:

resolve(root, args, context, info) {
    const topLevelFields = Object.keys(graphqlFields(info));
    return fetch(`/api/user?fields=${topLevelFields.join(',')}`);
}

答案 2 :(得分:0)

最好避免将所有内容压缩到一个分解程序函数中。而是为Cars创建一个单独的ObjectType,它具有自己的字段和自己的解析器功能。这样,仅在请求该字段时才调用汽车查询。

如果您使用的是RDS,请大声地加入数据和怪物,可以帮助优化查询的性能。

  • Join Monster依赖于生成一个大的联接查询,并且还解决了仅从数据库中准确请求您需要的字段的问题
  • Cached and Batched SQL Data Source,它在后台使用了Facebook的数据加载器-不会解决要查询哪些字段的问题(尽管该示例使用了knex,这将使操作变得容易得多),但是它可以缓存和批处理您的查询