Data modelling for ecommerce website using Amplify + GraphQL + DynamoDB - graphql

I'm using Amplify from AWS to build a small ecommerce project using React as frontend.
I'd like to know how I should write the "Product" and "Order" types in the schema in order to be able to write productId's to a product array in the Order table when users complete a purchase.
My schema.graphql file:
type Product #model {
id: ID!
name: String!
price: Int!
category: String!
images: [String]!
}
type Order #model {
id: ID!
products: [Product] #connection
}
My question is about the last line, do I need to define that [Product] connection there or I can use [String] to store product id's in a simple string array?

Point 1: In dynamoDB, you only need to define the data type of your partition key and sort key, and these can be string, number etc. For all the other attributes, you don't need to define anything.
Point 2: The dynamoDB designers prefer using a single table per application, unless it's impossible to manage data without multiple tables. Keeping this in mind, your table can be something like this.
Please observe: Only Id aka partition key and Sk aka sort key column is fixed here, all other columns can be anything per item. This is the beauty of DynamoDB. Refer to this document for dynamoDB supported data types.

Related

Can one combine two types to make a third in GraphQL schema syntax?

I have a feeling this will be deemed Not How You Do It In GraphQL, but I'm pretty new to it, so please be patient and verbose with me.
Let's say I've got two GraphQL types that I'd like to be able to utilize separately:
type UserSpecs {
name: String!
age: Int!
bio: String!
}
type UserCollections {
interests: [Interest]
buddies: [Relationship]
chats: [Chat]
}
type Query {
updateCollections(collections: UserCollections): User
updateUserSpecs(specs: UserSpecs): User
}
In my .gql file, I'd like to also define the User type as the combination of UserSpecs and UserCollections, though. In TypeScript, for instance, one would do this:
type User = UserSpecs & UserCollections
Short of manually duplicating the contents of UserSpecs and UserCollections into a third type, which would not be DRY and would create two sources of truth to maintain, does the GraphQL schema syntax have any way of combining two types to make a third?
Similarly, if it's possible to create a User type, then disassemble it into the UserSpecs and UserCollections types I'm after, that would be equally helpful.
Thank you in advance!

Architecture for avoiding repeated data in GraphQL

I have a application where the same data is present in many places in the graph and need to optimize the data queries to avoid processing and sending the same data too often.
As an example consider the following pseudo schema:
type Group {
name: String
members: [Person]
}
type Person {
name: String
email: String
avatar: Avatar
follows: [Person]
followedBy: [Person]
contacts: [Person]
groups: [Group]
bookmarks: [Bookmark]
sentMessages: [Message]
receivedMessages: [Message]
}
type Message {
text: String
author: Person
recipients: [Person]
}
type Bookmark {
message: Message
}
Querying a users data can easily contain hundreds, if not thousands, of Person-objects even though it the small circle of friends/contacts/follows only contains tens of distict users.
In my real implementation about 80% of each GraphQL query (in bytes) is redundant and considering that the client does many different queries in the same space above 90% of all data transferred and processed is redundant.
How could I improve the model so that I don't have to load the same data again and again without complicating the client too much?
I'm using Apollo for both GraphQL client and server.
Use/implement pagination (instead of just arrays) for relations - this way you can query for count/total (render it without array processing) and array of ids only - usually there is no need to query/join person table (DB) at all.
Render list of Person components (react?) using passed id prop only ... only rendered Person fetches for more details (if not cached, use batching to merge requests) consumed/rendered inside.

How can I pass arguements to child fields in Apollo?

I'm trying to build a graphql interface that deals with data from different regions and for each region there's a different DB.
What I'm trying to accomplish is:
TypeDefs= gql`
type Player {
account_id: Int
nickname: String
clan_id:Int
clan_info:Clan
}
type Clan{
name:
}
So right now I can request player(region, id), and this will pull up the player details no issues there.
But the issue is that Clan_info field also requires the region from the parent, so the resolver would look like clan_info({clan_id}, region).
Is there any way to pass down the region from parent to child field? I know I can add it to the details of the player, but would rather not since there would be millions of records and every field counts

How to encapsulate data of a type to be specific to the parent type in graphql

I have this game type:
type Game {
id: ID! #id
goals: [Goal]
}
which have a Goal relationship to:
type Goal {
id: Int! #id(strategy: SEQUENCE) #sequence(name: "IncID", initialValue: 1, allocationSize: 20)
thumbnail: String!
player: String!
minute: Int!
}
what i'm trying to do by that "id" mess is to create an incremental id value for the goal, for the purpose of creating a url for each goal, like this:
domaine.com/game/{id-of-the-game}/goal/{incremental-id(1,2..)}
the problem is, the Goal type looks like it is an entity of its own, it is gonna keep the last incremented id even if it is new game.
so i want to reset the id sequence for each new game.
What you ask for is not possible using the #id annotation. Each type in the prisma model needs to have a unique id to identify the object in the database. If the underlying database used is MongoDB there will be a Goal collection with documents in it, each representing an individual Goal identified by the id. If the underlying database used is MySQL/PostgreSQL the Goals will be stored in a Goal table with each row representing an individual Goal.
Each individual object (no matter if it is stored as a document or row) needs to be uniquely identified to access it and to create relations, e.g. between Goal objects and Game objects.
If the Goal id would start at 1 for each Game this would violate the unique constraint for the id field since two Goals in the table or collection would be identified by the same id (e.g. 1).
What I would suggest is to simply add something like a "numberInGame" field to the Goal type and fill it while creating the Goal (e.g. by taking goals.length in the Game.type into consideration).
Hope that helped to clarify the id field uniqueness constraint.

How do I setup query cache results for built in doctrine2 repository functions?

I have a site that is for a video game I play and am working on improving the performance of the site by implementing some additional caching. I've already been able to implement query result caching on custom repository functions, but haven't been able to find anywhere that explains how I can include query result caching on the built in functions (findOneById, etc). I'm interested in doing this because many of my database queries are executed from these 'native' repository functions.
So as an example I have a character entity object with the following properties: id, name, race, class, etc.
Race and class in this object are references to other entity objects for race and class.
When I load a character for display I get the character by name (findOneByName) and then in my template I display the character's race/class by $characterObject->getRace()->getName(). These method calls in the template result in a query being run on my Race/Class entity tables fetching the entity by id (findOneById I assume).
I've attempted to create my own findOneById function in the repository, but it is not called under these circumstances.
How can I setup doctrine/symfony such that these query results are cache-able?
I am running Symfony 2.1.3 and doctrine 2.3.x
I've found out that it isn't possible to enable query cache on doctrine build in functions. I will post a link which explains why later after I find it again.
Your entities probably look something like this:
MyBundle\Entity\Character:
type: entity
table: Character
fields:
id:
id: true
type: bigint
name:
type: string
length: 255
manyToOne:
race:
targetEntity: Race
joinColumns:
raceId:
referencedColumnName: id
MyBundle\Entity\Race:
type: entity
table: Race
fields:
id:
id: true
type: bigint
name:
type: string
length: 255
oneToMany:
characters:
targetEntity: Character
mappedBy: race
If that's the case, then modify your Character entity mapping so that it eagerly loads the Race entity as well:
MyBundle\Entity\Character:
...
manyToOne:
race:
targetEntity: Race
joinColumns:
raceId:
referencedColumnName: id
fetch: EAGER
Doctrine documentation on the fetch option: #ManyToOne

Resources