繁体   English   中英

如何使用 Laravel Lighthouse 创建一个 GraphQL 查询,该查询从一个字段中的多个表/模型返回数据

[英]How to create a GraphQL query that returns data from multiple tables/models within one field using Laravel Lighthouse

我正在尝试使用 Laravel 和 Lighthouse 学习 GraphQL 并且有一个问题希望有人可以帮助我。 我有以下五个数据库表,它们也在我的 Laravel 模型中定义:

  • 用户
  • 图书
  • user_books
  • 系列书籍
  • book_copies

我想创建一个 GraphQL 端点,它允许我取回一组用户和他们拥有的书籍,在那里我可以将多个表中的数据提取到一个名为“书籍”的子字段中,如下所示:

query {
    users {
        name
        books {
            title
            issue_number
            condition
            user_notes
        }
    }
}

要在 SQL 中完成此操作,使用如下连接很容易:

$users = User::all();
foreach ($users as $user) {
    $user['books'] = DB::select('SELECT 
        book_series.title,
        book.issue_number
        book_copies.condition, 
        user_books.notes as user_notes
    FROM user_books 
    JOIN book_copies ON user_books.book_copy_id = book_copies.id 
    JOIN books ON book_copies.book_id = books.id 
    JOIN book_series ON books.series_id = book_series.id 
    WHERE user_books.user_id = ?',[$user['id']])->get();
}

How would I model this in my GraphQL schema file when the object type for "books" is a mashup of properties from four other object types (Book, UserBook, BookCopy, and BookSeries)?

编辑:通过执行如下查询,我能够获得所需的所有数据:

users {
    name
    userBooks {
      user_notes
      bookCopy {
        condition
        book {
          issue_number
          series {
            title
          }
        }
      }
    }
}

但是,如您所见,数据被分成多个子对象,不如将所有数据放在一个平面“书籍”object 中那么理想。 如果有人知道我如何将所有数据恢复到一个平面 object 中,我很想知道。

我还注意到,关系的字段名称需要与每个 model 中的 controller 方法名称完全匹配,根据 Laravel 命名约定,它们是驼峰式。 除了我的其他字段与lower_underscore 的数据库列名匹配。 这是一个轻微的挑剔。

好的,在您编辑完您的问题后,我将在此处写下答案,以回答您的新问题。

但是,如您所见,数据被分成多个子对象,不如将所有数据放在一个平面“书籍”object 中那么理想。 如果有人知道我如何将所有数据恢复到一个平面 object 中,我很想知道。

问题是,这种获取数据是 GraphQL 的中心思想。 你有一些类型,这些类型之间可能有一些关系。 因此,您可以获取 object 的任何关系,任何深度,甚至循环。 Lighthouse 为您提供对 eloquent 关系的开箱即用支持与批量加载,避免了 N+1 性能问题。 您还必须记住 - GraphQL 定义中的每个字段(字面意思是每个字段)都在服务器上解析。 因此,每个字段都有一个解析 function。 因此,您可以自由地为特定字段编写自己的解析器。 您实际上可以在 GraphQL 中定义一个符合您最初期望的类型。 然后您可以定义一个根查询字段,例如fetchUsers ,并创建您的自定义字段解析器。 您可以阅读文档,了解它的工作原理以及如何实现: https://lighthouse-php.com/5.2/the-basics/fields.html#hello-world在此字段解析器中,您可以自己制作数据获取,即使不使用任何 Laravel/Eloquent API。 您必须注意的一件事 - 为该字段返回与 GraphQL 中的返回类型相同结构的正确数据类型。

总而言之-您可以选择这样做。 但在我看来,你必须编写更多自己的代码,并用你自己的测试来覆盖它,结果证明你需要做更多的工作。 我认为使用内置指令更简单,例如@find@paginate@all结合关系指令,它们都包含测试,而不关心实现。

我还注意到,关系的字段名称需要与每个 model 中的 controller 方法名称完全匹配,根据 Laravel 命名约定,它们是驼峰式。

您可能指的是 Model class 中的方法,而不是 controller。 Lighthouse 提供了一个@rename指令,您可以使用它在 GraphQL 中为您的属性定义不同的名称。 对于关系指令,您可以传递一个relation参数,该参数将用于获取数据。 所以对于你的例子,你可以使用这样的东西:

type User {
   #...
   user_books: [Book!]! @hasMany(relation: "userBooks")
}

但是在我们的项目中,我们决定将 snak_case 也用于关系,以保持 GraphQL 干净,并使用一致的命名约定和更少的工作量

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM