2017-02-09 58 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/