Как использовать итераторы и Async ожидают запроса таблицы ключей облака Google T1 при запросе второй таблицы T2 для каждой записи в T1 - PullRequest
0 голосов
/ 28 сентября 2018

У меня есть две таблицы в базе данных облачного гаечного ключа Google - Авторы и Книги.

const request = {schema: [CREATE TABLE Authors ( AuthorId INT64 NOT NULL, FirstName STRING(1024), LastName STRING(1024), AuthorInfo BYTES(MAX) ) PRIMARY KEY (AuthorId), CREATE TABLE Books ( AuthorId INT64 NOT NULL, BookId INT64 NOT NULL, BookTitle STRING(MAX) ) PRIMARY KEY (AuthorId, BookId), INTERLEAVE IN PARENT Authors ON DELETE CASCADE,],};

export async function findAuthorBooks(authorId) {
  // [START spanner_find_author_books]
  const database = instance.database(databaseId);
  const query = {
    sql: "SELECT * FROM Books As t WHERE t.AuthorId = @authorId",
    params: { authorId },
    types: { authorId: "string" },
  };

  const results = await database.run(query);
  const rows = results[0];
  const result = [];
  rows.forEach((row) => {
    const json = row.toJSON();
    result.push(json);
  });
  database.close();
  if (Array.isArray(result)) return result;
  throw new Error("err");
  // [END spanner_find_author_books]
}

Теперь я хочу запросить всех авторов и для каждого автора я запрашиваю всеего книги и добавить его как объект.Функция findAuthor1 () прекрасно работает.

export async function findAuthors1() {
  // [START spanner_find_authors]
  const database = instance.database(databaseId);
  const results = await database.run({ sql: "SELECT * FROM Authors" });
  const rows = results[0];
  const result = [];
  for (const row of rows) {
    const json = row.toJSON();
    const id = json.vendorId;
    json.notification = await findAuthorBooks(id);
    result.push(json);
  }
  database.close();
  if (Array.isArray(result)) return result;
  throw new Error("err");
  // [END spanner_find_authors]
}

Но проблема здесь в том, что итераторам / генераторам требуется время выполнения регенератора, которое слишком тяжело для этого руководства, чтобы их разрешить.Отдельно следует избегать циклов в пользу итераций массива (согласно Eslint).Итак, я решил использовать Promise.all, как показано ниже в функции findAuthors2 ():

export async function findAuthors2() {
  // [START spanner_find_authors]
  const database = instance.database(databaseId);
  const results = await database.run({ sql: "SELECT * FROM Authors" });
  const rows = results[0];
  const result = [];

  await Promise.all(rows.map(async (row) => {
    const json = row.toJSON();
    const id = json.vendorId;
    json.notification = await findAuthorBooks(id);
    result.push(json);
  }));
  database.close();
  if (Array.isArray(result)) return result;
  throw new Error("err");
  // [END spanner_find_authors]
}

К сожалению, она не работает.Итак, как я могу заставить это работать или есть другой (лучший) способ сделать это без необходимости использовать Promise.all?Или есть способ написать подзапрос, который выберет Книги в качестве массива структур и добавит к основному запросу, выбрав Авторы?

1 Ответ

0 голосов
/ 28 сентября 2018

Или есть способ написать подзапрос, который выберет Книги в качестве массива структур и добавит к основному запросу, выбрав Авторы?

Да - используя подзапрос, который возвращает массивструктур: (см. Примечания о подзапросах в документах Spanner SQL)

например:

SELECT 
  a.AuthorId, 
  a.FirstName, 
  a.LastName, 
  a.AuthorInfo,
  ARRAY(SELECT AS STRUCT
          b.BookID, b.BookTitle
        FROM
          Books b
        WHERE
          a.AuthorId = b.AuthorId) as Books
FROM
  Authors a;

Вам придется распаковать массив структур, который возвращается какСтолбец книг в вашем коде ...

Существует также более простой метод: просто объедините две таблицы и получите строку для каждой комбинации автор / книга и определите в своем коде, когда AuthorID изменит

SELECT 
  a.AuthorId, 
  a.FirstName, 
  a.LastName, 
  a.AuthorInfo,
  b.BookID,
  b.BookTitle
FROM
  Authors a, Books b
WHERE
  a.AuthorID = b.BookID
ORDER BY
  a.AuthorID;
...