2017-02-09 27 views
0

我正在学习graphql,我想我已经发现了一个缺陷。 假设我们有模式这样只使用Graphql加载数据库所需的数据

type Hero { 
    name: String 
    friends: [Person] 
} 

type Person { 
    name: String 
} 

和两个查询

{ 
    hero { 
    name 
    friends { 
     name 
    } 
    } 
} 

{ 
    hero { 
    name 
    } 
} 

和关系数据库有两个对应表HerosPersons

如果我的理解是正确的,我不能解决这个查询,例如,对于第一个查询生成的SQL查询将

select Heros.name, Persons.name 
from Heros, Persons 
where Hero.name = 'Some' and Persons.heroid = Heros.id 

而对于第二

select Heros.name, Persons.name from Heros 

所以只有查询真正需要的字段将从数据库加载。

我说得对吗? 此外,如果graphql有能力只返回查询所需的数据,而不是对完整模式有效的数据,我认为这是可能的,对吧?

+0

@ p0k8_为什么不呢? – user1685095

+0

@ p0k8_'因为用户可能不会查询嵌套类型,所以对数据库自定义批处理请求并不好。如果用户没有查询嵌套类型,那么在sql中不应该有任何连接,就像我在第二个查询中显示的那样。要么你不明白我在问什么,要么我不明白你在说什么。 – user1685095

+0

这正是我在写[Join Monster](https://github.com/stems/join-monster)时打算解决的问题。它仅在实际请求嵌套类型时才生成SQL并动态添加联接。它可以任意深入,并与postgres(很快mariadb)分页。 –

回答

0

在Scala实现(桑格利亚-grahlQL),您可以通过以下实现这一点:

假设这是客户端查询:

query BookQuery { 
    Books(id:123) { 
     id 
     title 
     author { 
     id 
     name 
     } 
    } 
} 

这是Garphql Server的查询类型。

val BooksDataQuery = ObjectType(
    "data_query", 
    "Gets books data", 
    fields[Repository, Unit](
     Field("Books", ListType(BookType), arguments = bookId :: Nil, resolve = Projector(2, (context, fields) =>{ c.ctx.getBooks(c.arg(bookId), fields).map(res => res)})) 
    ) 
) 
val BookType = ObjectType(....) 
val AuthorType = ObjectType(....) 

Repository class: 

def getBooks(id: String, projectionFields: Vector[ProjectedName]) { 
/* Here you have the list of fields that client specified in the query. 
    in this cse Book's id, title and author - id, name. 
    The fields are nested, for example author has id and name. In this case author will have sequence of id and name. i.e. above query field will look like: 
    Vector(ProjectedName(id,Vector()), ProjectedName(title,Vector()),ProjectedName(author,ProjectedName(id,Vector()),ProjectedName(name,Vector()))) 

    Now you can put your own logic to read and parse fields the collection and make it appropriate for query in database. */ 
} 

在你的查询类型的字段resolver客户因此,基本上,你可以拦截指定的字段。

+0

好的,很好!奇怪的是,没有这样的例子在graphql站点中。这是什么样的黑客,斯卡拉图书馆呢... – user1685095

+0

是的,官方graphql网站不提供太多,因为小社区,谷歌也没有多大帮助。顺便说一句,有几个graphql [链接](http://graphql.org/code/)的服务器端框架,上面的是用于scala的** Sangria Graphql **。你应该尝试检查这些框架的github,并通过演示项目和代码。 –

2

是的,这是绝对有可能和鼓励。但是,它的要点在于,除非明确说明如何获取数据,否则GraphQL基本上不了解您的存储层。关于这一点的好消息是,无论数据在哪里,您都可以使用graphql来优化查询。

如果您使用javascript,那么可以通过理解选择集来简化您的生活。它看起来像这样。

如果你有此查询

query GetCityEvents { 
    getCity(id: "id-for-san-francisco") { 
    id 
    name 
    events { 
     edges { 
     node { 
      id 
      name 
      date 
      sport { 
      id 
      name 
      } 
     } 
     } 
    } 
    } 
} 

然后解析器可能是这样的

import graphqlFields from 'graphql-fields'; 

function getCityResolver(parent, args, context, info) { 
    const selectionSet = graphqlFields(info); 
    /** 
    selectionSet = { 
     id: {}, 
     name: {}, 
     events: { 
     edges: { 
      node: { 
      id: {}, 
      name: {}, 
      date: {}, 
      sport: { 
       id: {}, 
       name: {}, 
      } 
      } 
     } 
     } 
    } 
    */ 
    // .. generate sql from selection set 
    return db.query(generatedQuery); 
} 

还有更高级别的工具,如join monster,可能这方面的帮助。

这是一篇博文,更详细地介绍了其中一些主题。 https://scaphold.io/community/blog/querying-relational-data-with-graphql/