I'm exploring amplify with typescript by making a library and have set up a many-to-many connection
type Book @model {
# ! means non-null GraphQL fields are allowed to be null by default
id: ID!
name: String!
picture: String!
genres: [BookGenre] @connection(keyName: "byBook", fields: ["id"])
createdAt: String!
userId: String!
}
type BookGenre
@model(queries: null)
@key(name: "byBook", fields: ["bookID", "genreID"])
@key(name: "byGenre", fields: ["genreID", "bookID"]) {
id: ID!
bookID: ID!
genreID: ID!
book: Book! @connection(fields: ["bookID"])
genre: Genre! @connection(fields: ["genreID"])
}
type Genre @model {
id: ID!
name: String!
createdAt: String!
books: [BookGenre] @connection(keyName: "byGenre", fields: ["id"])
}
I can create a new book and add the user provided genres like this
const handleSubmit = async (evt) => {
evt.preventDefault();
const createdAt = new Date().toISOString();
const bookID = hash(name);
const book: CreateBookInput = {
id: bookID,
name,
picture: "",
createdAt: createdAt,
userId: "faked"
};
try {
await API.graphql(
graphqlOperation(createBook, {
input: book
})
);
for (const t of tags) {
const genreID = hash(t)
const genre: CreateGenreInput = {
id: genreID, name: t, createdAt
}
await API.graphql(graphqlOperation(createGenre, {input: genre}))
const bookGenre: CreateBookGenreInput = {
bookID, genreID
}
await API.graphql(graphqlOperation(createBookGenre, {input: bookGenre}))
}
setName("")
} catch (e) {
console.error(e)
}
}
This might not be the best way to do it! As it is many writes for each book but I can see the genres and their join records being written to Dynamo
I want to load a page that lists all of the books.
I've done this by:
let result;
try {
result = await API.graphql(graphqlOperation(listBooks));
} catch (err) {
console.warn(err);
return { props: { books: [] }};
}
if (result.errors) {
console.warn("Failed to fetch books. ", result.errors);
return { props: { books: [] }};
}
const queryResult: ListBooksQuery = result.data
if (queryResult.listBooks !== null) {
let books = queryResult.listBooks.items
return { props: { books }};
}
return { props: { books: [] }};
But this doesn't load the genres...
I'm guessing I need to query through @key(name: "byBook", fields: ["bookID", "genreID"])
but I'm not understanding how to do that by looking at the generated code...
I'm new to amplify and to graphql so am assuming I'm missing something trivial :)
What's the correct way to query for a list of all items and their children through a many-to-many relationship?
It seems
amplify
does not correctly generate the queries.I assume your generated query looks something like this:
In order to load the
Genre
as well, you need to modify the query to:genres.items
will load all the entities from the join table.genre
will then load the field on the entity, which references theGenre
table.