I have a book database looking like this (simplified):
[book]
- bookId
- title
[author]
- authorId
- name
[book_has_author]
- bookId
- authorId
So basically a book can have multiple authors and an author can have multiples books.
I created an express API that retrieve me a list of books with his authors with an inner join. Here is what it returns for one book having 2 authors:
[
{
bookId: 1,
title: "how to code",
authorId: 1,
name: "martin"
},
{
bookId: 1,
title: "how to code",
authorId: 2,
name: "Tim"
}
]
But my Angular models looks like this:
interface Author {
authorId: number,
name: string,
books: Book[]
}
interface Book {
bookId: number,
title: string,
authors: Author[]
}
I know it's a bad way to represent my database but I don't know how I can model it.
The main issue here is that interfaces have circular referencies to each other, although I imagine you already figured that out. This is generally a problem and although it's technically correct to think about the data in those terms it's not a good approach to model your data.
The first solution would be to make a choice between having an author have-books or a book have-authors, thus removing one of the dependencies out of the circular reference. You could also create BookChild
and AuthorChild
interfaces while keeping the Book
and Author
ones, but that will end up adding unnecessary complexities if the use case isn't really worth it.
After making your choice, you would probably need to add some type safety in your query results. To do that you can create a BookAuthorResponse
interface and then transform it to a Book
through map and reduce operations or the imperative equivalent (for-loop).
interface Author {
authorId: number,
name: string
}
interface Book {
bookId: number,
title: string,
authors: Author[]
}
interface BookAuthorResponse {
bookId: number
title: string
authorId: number
name: string
}
const bookAuthorResponseArray: BookAuthorResponse[] = [
{
bookId: 1,
title: "how to code",
authorId: 1,
name: "martin"
},
{
bookId: 1,
title: "how to code",
authorId: 2,
name: "Tim"
}
]
const books: Book = bookAuthorResponseArray.map(ba => ({
bookId: ba.bookId,
title: ba.title,
authors: [{
authorId: ba.authorId,
name: ba.name
}]
}))
.reduce((ba, acc) => ({
bookId: ba.bookId,
title: ba.title,
authors: [...acc.authors, ba.authors[0]]
}))