GraphQL如何仅在需要时使解析器获取数据?

时间:2018-05-26 23:26:17

标签: javascript typescript relational-database graphql

我有两种GraphQL类型:

type Author {
  id: String!
  name: String!
}

type Book {
  id: String!
  author: Author!
  name: String!
}

在我的数据库中,它由books表中的外键实现:

authors (伪代码)

`id` INTEGER UNSIGNED
`name` STRING

books (伪代码)

`id` INTEGER UNSIGNED
`author_id` INTEGER UNSIGNED REFERENCE `authors.id`
`name` STRING

所以,当我解决GraphQL查询时,如:

query allTheBooks {
  id
  name
  author {
    id
  }
}

我不想再进行另一个SQL查询而不是获取书籍列表的查询,因为我已经拥有books.author_id字段中的数据。

所以我替换下面的代码(js):

Book: {
  async author(book, args, context, info) {
    // this code trigger a database SELECT query that fetch all the fields of the author row associated with the book
    return book.author().get();
  }
}

由:

Book: {
  async author(book, args, context, info) {
    return {
      id: book.author_id,
    }
  }
}

它运作良好!

我只有1个SQL查询,其中我有1 + N(N是第一个查询返回的行数)。

但是如何在不按字段发送查询的情况下返回其他字段?

我想通过返回所有字段的唯一承诺是可能的,这将取决于author行的所有内容,但我想知道是否有更清洁的方式......

提前感谢您的回答!

2 个答案:

答案 0 :(得分:0)

现在,我发现一种或多或少干净的方法:

Book: {
  async author(book, args, context, info) {
    let authorPromise = null;

    async function getAuthor() {
      if (authorPromise === null) {
        authorPromise = book.author().get();
      }

      return authorPromise;
    }

    return new Proxy({}, {
      async get({}, name) {
        if (name === "id") {
          return book.author_id;
        }

        if (name in authorFields) {
          const author = await getFile();
          return author[name];
        }
      },
    });
  }
}

它确保我每行只进行一次查询,但是给我留下关于加入表的另一个问题,但我会发布它{ - 3}}: - )

答案 1 :(得分:0)

您不必进行1 + N查询。您可以将N个查询批处理为1.只需查看https://github.com/facebook/dataloader