在graphQL服务器中用SQL datasarouce实现嵌套游标分页的最佳方法是什么?

时间:2019-07-11 08:20:41

标签: sql graphql graphql-js relay

您如何在Relay-esk模式(使用SQL数据源)中使用嵌套游标管理有效的数据提取?

  1. 您是否尝试通过“ LIMIT args_first”,“ ORDER BY args_orderby”和“ WHERE cursor>:args_after”进行单个复杂的SQL查询来解决N + 1问题
  2. 您是否对数据库运行2个查询并利用facebook数据加载器?

例如,我有一个结构如下:

enum BookSortKeys {
    ID,
    TITLE,
    PRICE,
    UPDATED_AT,
    CREATED_AT
}
enum ReviewSortKeys {
    ID,
    REVIEW,
    UPDATED_AT,
    CREATED_AT
}
type Book {
  id: ID!
  title: String!
  description: String
  price: Float!
  updatedAt: String!
  createdAt: String!
  reviews("""
    Returns the elements that come after the specified cursor.
    """
    after: String
    """
    Returns the elements that come before the specified cursor.
    """
    before: String
    """
    Returns up to the first `n` elements from the list.
    """
    first: Int
    """
    Returns up to the last `n` elements from the list.
    """
    last: Int
    """
    Reverse the order of the underlying list.
    """
    reverse: Boolean = false
    """
    Sort the underlying list by the given key.
    """
    sortKey: ReviewSortKeys = ID): ReviewConnection!
}
type Query {
  books("""
    Returns the elements that come after the specified cursor.
    """
    after: String
    """
    Returns the elements that come before the specified cursor.
    """
    before: String
    """
    Returns up to the first `n` elements from the list.
    """
    first: Int
    """
    Returns up to the last `n` elements from the list.
    """
    last: Int
    """
    Supported filter parameters:
     - `title`
     - `id`
     - `price`
     - `description`
     - `created_at`
     - `updated_at`
    """
    query: String
    """
    Reverse the order of the underlying list.
    """
    reverse: Boolean = false
    """
    Sort the underlying list by the given key.
    """
    sortKey: BookSortKeys = ID): BookConnection!
}
type ReviewConnection {
    pageInfo: PageInfo!
    edges: [ReviewEdge!]!
}
type ReviewEdge {
    cursor: String!
    node: Review!
}
type BookConnection {
    pageInfo: PageInfo!
    edges: [BookEdge!]!
}
type BookEdge {
    cursor: String!
    node: Book!
}
type PageInfo {
    hasNextPage: Boolean!
    hasPreviousPage: Boolean!
}
type Review {
    review: String!
    id: ID!
    updatedAt: String!
    createdAt: String!
}
type Mutation {
}
schema {
  query: Query
  mutation: Mutation
}

我想执行如下查询,并以最有效的方式检索数据。

query GET_BOOKS {
  books(first:10, sortKey: PRICE, reverse: true) {
       pageInfo {
      hasNextPage
      hasPreviousPage
    } 
    edges {
      cursor
      node {
        id
        title
        description
        reviews(after:"base64-cursor" first: 5, sortKey: CREATED_AT) {
          edges {
            node{
              review
            }
          }
        }
      }
    }
  }
}

我可以很容易地将顶部查询(书)的所有分页参数转换为sql语句,但是使用嵌套游标,我只能看到2个选项(如上所述)...之前遇到的当前问题实现这些选项的是:

  1. 如果我采用纯SQL方法-甚至还有一种干净的方法来运行单个查询并在嵌套(JOIN)级别应用LIMITWHERE createdAt > :after_cursor_val
  2. 如果可以做到以上几点,那么它是否比大规模的数据加载器更具性能?由于查询似乎很复杂,如果实施的话。
  3. 如果嵌套的分页树变大(即具有4个嵌套的分页的请求),会发生什么?这里纯查询对象级别的sql命令就足够了吗?还是在每个关系上添加解析器更具伸缩性(例如,书->评论有一个sql查询以拉出本书的所有特定评论,评论->出版物有一个查询以拉出它曾参与的所有评论的特定出版物,依此类推,等等。在数据加载器中批处理它们)
  4. 如果您走数据加载器路线,则批处理似乎使用了“ WHERE IN”子句(即SELECT * FROM reviews "reviews" WHERE "reviews".bookId IN (...list of book ids batched)-将添加LIMITORDER BYWHERE createdAt > :cursor,出乎意料的结果,因为我的结果集是多个“书本ID”中条目的混合?
  5. 从长远来看,我个人的感觉是,从代码角度来看,纯sql方法会变得混乱,对此有何想法?

0 个答案:

没有答案