如何使用迭代器和异步等待查询 google cloud spanner table T1,同时为 T1 中的每条记录查询第二个 table T2
How to use iterators and Async await to query a google cloud spanner table T1 while querying a second table T2 for each record in T1
我在 Google 云扳手数据库中有两个表 - 作者和书籍。
const 请求 = {
模式:[
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]
}
但这里的问题是,iterators/generators 需要 regenerator-runtime,这对于本指南来说太重量级了,无法允许它们。另外,应该避免循环以支持数组迭代(根据 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?
要么
有没有办法编写一个子查询,将 select Books 作为结构数组添加到主查询 selecting Authors?
Or Is there a way to write a subquery that will select Books as Array
of structs and add to the main query selecting Authors?
是- 使用子查询,其中 returns 一个结构数组:
(请参阅 Spanner SQL 文档中的 Notes about Subqueries)
例如:
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;
您将必须解压缩作为代码中的 Books 列返回的结构数组...
还有一个更简单的方法:只需连接 2 个表并为每个 author/book 组合获取一行,并在 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;
我在 Google 云扳手数据库中有两个表 - 作者和书籍。
const 请求 = {
模式:[
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]
}
但这里的问题是,iterators/generators 需要 regenerator-runtime,这对于本指南来说太重量级了,无法允许它们。另外,应该避免循环以支持数组迭代(根据 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? 要么 有没有办法编写一个子查询,将 select Books 作为结构数组添加到主查询 selecting Authors?
Or Is there a way to write a subquery that will select Books as Array of structs and add to the main query selecting Authors?
是- 使用子查询,其中 returns 一个结构数组: (请参阅 Spanner SQL 文档中的 Notes about Subqueries)
例如:
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;
您将必须解压缩作为代码中的 Books 列返回的结构数组...
还有一个更简单的方法:只需连接 2 个表并为每个 author/book 组合获取一行,并在 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;