Apollo/React mutating two related tables - graphql

Say I have two tables, one containing products and the other containing prices.
In Graphql the query might look like this:
option {
id
price {
id
optionID
price
date
}
description
}
I present the user with a single form (in React) where they can enter the product detail and price at the same time.
When they submit the form I need to create an entry in the "product" table and then create a related entry in the "price" table.
I'm very new to Graphql, and React for that matter, and am finding it a steep learning curve and have been following an Apollo tutorial and reading docs but so far the solution to this task is remaining a mystery!
Could someone put me out of my misery and give me, or point me in the direction of, the simplest example of handling the mutations necessary for this?

Long story short, that's something that should actually be handled by your server if you want to optimize for as few requests as possible.
Problem: The issue here is that you have a dependency. You need the product to be created first and then with that product's ID, relate that to a new price.
Solution: The best way to implement this on the server is by adding another field to Product in your mutation input that allows you to input the details for Price as well in the same request input. This is called a "nested create" on Scaphold.
For example:
// Mutation
mutation CreateProduct ($input: CreateProductInput!) {
createProduct(input: $input) {
changedProduct {
id
name
price {
id
amount
}
}
}
}
// Variables
{
input: {
name: "My First Product",
price: {
amount: 1000
}
}
}
Then, on the server, you can parse out the price object in your resolver arguments and create the new price object while creating the product. Meanwhile, you can also relate them in one go on the server as well.
Hope this helps!

Related

How to update Saleor's Graphql responses with newly added DB table fields?

First, Saleor with GraphQL is fantastic. Just love it.
The products we are selling have additional metadata we need to get from Graphql. Out of the box, the Graphql queries work fine, such as:
{
product (id: "UHJvZHVjdDo3Mg==") {
id
name
description
}
}
What I need to do is expose data from my products table with additional columns, such as productInfo1, productInfo2, and productInfo3. This part is easy of course.
However, I am struggling with how to update the Saleor Graphql so I can run a query like the following:
{
product (id: "UHJvZHVjdDo3Mg==") {
id
name
description {
productInfo1
productInfo2
productInfo3
}
}
}
I have been through the Saleor docs, Stack Overflow, and a variety of blogs... I've attempted some logical approaches myself, without any success.
I'm eager to start working on these types of updates for our needs here. Any suggestions or links to "how to" locations would be greatly appreciated!
If you'd like to add subfields to description there is a couple of things you have to do:
Create new description object type which contains the subfields you want, e.g.:
class ProductDescription(graphene.ObjectType):
productInfo1 = graphene.String()
productInfo2 = graphene.String()
productInfo3 = graphene.String()
Set the description field with the new type under Product type:
class Product(CountableDjangoObjectType):
...
description = graphene.Field(ProductDescription)
Add resolver for description under Product type:
def resolve_description(self, info):
return ProductDescription(
productInfo1=self.description,
productInfo2='Some additional info',
productInfo3='Some more additional info',
)
Saleor's GraphQL API is based on the Graphene framework. You can find more about resolvers and object types here: https://docs.graphene-python.org/en/latest/types/objecttypes/#resolvers.

GraphQL: Is it possible to search nested field?

I am specifically using the shopify graphql admin api to query orders.
I want to do a search for a nested related field.
Below is my query.
export const orderHistoryQuery = gql`
query Order($productsFirst: Int!, $productsAfter: String, $filterQuery: String) {
orders(first: $productsFirst, after: $productsAfter, reverse: true, query:$filterQuery) {
edges {
cursor
node {
id
name
customer {
id
metafields(first: 10) {
edges {
node {
id
key
value
namespace
}
cursor
}
}
}
totalPriceSet {
shopMoney {
amount
currencyCode
}
}
subtotalPriceSet {
shopMoney {
amount
currencyCode
}
}
totalRefundedSet {
shopMoney {
amount
currencyCode
}
}
currencyCode
email
phone
processedAt
totalShippingPriceSet {
shopMoney {
amount
currencyCode
}
}
totalTaxSet {
shopMoney {
amount
currencyCode
}
}
shippingAddress {
firstName
lastName
address1
address2
city
province
zip
country
}
billingAddress {
firstName
lastName
address1
address2
city
province
zip
country
}
customAttributes {
key
value
}
}
}
}
}
`;
I want to query metafields or ANYTHING really but it doesn't seem like it's supported. I am not sure if I just have the wrong query syntax or if it's not supported. The shopify search syntax documenation doesn't really help and this is where my knowledge of graphql falls apart.
Is it possible to do this in graphql? I also tried adding metafields(id: $whateverID) which is not supported by their setup.
Unfortunately, Shopify doesn't support query filters on metafields. The best way to figure this out is by using a graphql explorer like GraphiQL. Shopify dashboard has this built in if you go to Apps > Shopify GraphiQL App.
Using GraphiQL you can see that:
Customers query doesn't have metafields supported:
Orders query doesn't have customers or metafields supported:
And metafields on customers doesn't have a query param:
I think your options are to either query by what you can and filter after you get the results or use a customer tag and query by tag.
You would really help your cause out by simplifying things. My advice to you is to try a simple query. Can you get an order? Since an order has a customer (usually but not always), can you get a metafield associated with that customer?
You have so many obstacles in your attempt to show what you are trying to do, it is almost as if you want a migraine headache in trying to debug anything. GraphQL calls to endpoints are documented fairly well from the GraphQL website perspective, and Shopify is nothing but a vanilla implementation of that, with the caveat that they charge you for calls based on complexity, so you had best be monitoring your credits.
So ya, try simple calls. Get a product and it's Metafields. Get a customer record and it's Metafields. If you can do that, you are not challenging the documentation much, nor the concept of GraphQL queries. Once a basic all works, you can work in variables, cursors, paging, etc... but until a one-off call gives you what you want, debugging should be concentrated on the simplest of calls, not everything and the kitchen sink.
Also, when you screw up a call to the endpoint, Shopify usually returns a response with details about where you screwed up, providing you with a first place to look. We see nothing of your response, so there is little to go on to help you.

GraphQL with multiple objects: should I keep all objects in a single query?

I´m building a SaaS B2B application composed of several different objects. Examples:
Users
Customers
StockItens
StockLevels
PriceList
Sales
Returns
Etc...
I´ll have around 40 different objects, that can be listed and created, edited, and deleted individually.
Facing the GraphQL concepts for the first time, should I build a large schema for all objects, like the example below, or should I keep each object on its own query.
query {
viewer {
Users {
id
firstName
lastName
address
city
...
}
Customers {
id
firstName
lastName
address
city
rating
...
}
StockItens {
id
item_id
sales {
id
dateTime
qty
unitValue
totalValue
...
}
...
}
StockLevels {
...
}
PriceList {
...
}
Sales {
id
dateTime
qty
unitValue
totalValue
...
}
Returns {
...
}
}
}
Looking for the first option (keeping everything into one single query) seens logical as I will be using fragments to access the desired piece of information, but then I will have a huge schema with lots of inter relations.
PLease advice what would be the best practice on that use case.
I suggest you do not write a query where you add all needed data but use the concept of fragments as you already pointed out.
And you fetch only the data which are needed for the current page. So the throughput is kept minimal.
e.g.
If you have a page where you update a user you just fetch the needed data for this user in a specialized query. The query consists of fragments.
The fragments are related to the subcomponents which are used in the page, for example a form where you show the data of the user.
The fragment of the form defines the data it needs from the user and the update page combines the fragments to the query.
// in user form component
const userFormFragments = {
name: "UserForm",
document: `fragment UserForm on User {
id
name
}`
};
// in update user page
const userQuery = `query getUserQuery($userId: ID!) {
getUser(userId: $userId) {
...${userFormFragment.name}
}
${userFormFragment.document}
}`

Elasticsearch: document relationship

I'm doing a elastic search autocomplete-as-you-type
I'm using cool features like ngram's and other stuff to create needed analyzer.
currently I break my had around indexing following data.
Let say I have Payments type,
each document in this type looks like this
{
..elastic meta data..
paymentId: 123453425342,
providerAccount : {
id: 123456
firstName: Alex,
lastName: Web
},
consumerAccount : {
id: 7575757,
firstName: John,
lastName: Doe
},
amount: 556,
date : 342523454235345 (some unix timestamp)
}
so basically this document represents not only the payment itself but it also shows the relationship of the payment, the 2 entities which related to the payment.
Payment always have its provider and consumer.
I need this data in payment document because I want to show it in UI.
By indexing it like so, it might be a big pain for handling the updates of Consumer or Provider because each time some of them change its properties I have to update all the payments which has this entity.
Another possible solution is to store only id's of this consumers/providers and make a query on payments and then 2 queries for the entities for retrieving needed fields, but i'm not sure about this because i'm doing ajax requests each time a character entered, so here comes the performance question.
I have also looked into parent/child relationship solution which basically fits my case but I wasn't able to figure out if I can retrieve also the parent(consumer/provider) fields while I querying child(payment).
What would you suggest?
Thanks!
Yes, you can retrieve the parent while querying child using has_child.
Considering payment as child and consumer as parent, You can search all the consumers by :
GET /index_name/consumer/_search
{
"query": {
"has_child": {
"type": "payment",
"query": {
// any query on payment table
},
"inner_hits": {}
}
}
}
This would fetch you all the consumer based on the query on child i.e payment in your case.
inner_hits is what you are looking for. This will retrieve you the children as well. But it was introduced in elasticsearch 1.5.0. So version should be greater than elasticsearch 1.5.0.
You can refer https://www.elastic.co/blog/elasticsearch-1-5-0-released.
Your problem is not an issue. I suppose you want tot freeze data after the pay, right? So you don't need to update the accounts data in existing payment documents.
Further: parent/schild is easy for updating, but less efficient with querying. For auto complete, stay using your current mapping!

Which of the following data structures is scalable in elasticsearch?

I want to build an event analytics system, where I can record and query events that a user has done, for example on a website.
My naive idea of the data model was simply a collection of event documents, each event including the userid, event type, and so on. So I thought something like this:
{ userid: Joe, event: homepage }
{ userid: Mike, event: homepage }
{ userid: Joe, event: productsPage }
{ userId: Joe, event: accountSettings }
{ userId: Joe, event: checkout }
etc
But now I'm struggling to figure out how to do some of the queries I'm most likely to be able to want to do.
For example, I want to say "Give me a list of all users who have visited the homepage AND the products page AND the checkout page"
Seems to me I would need to use my application code to do this, rather than elasticsearch? And I would need to do something like:
Step 1: select all users who have done 'homepage'
Step 2: select all users who have done 'products page'
Step 3: select all users who have done 'checkout page'
Step 4: build a list of only those users who appear in all 3 lists.
If I have a userbase of 20 million users, I risk bringing huge lists of data into my application?
An alternative would be to have one document per user, so that Joe looks like
{ userid: Joe, event: [ homepage, productsPage, accountSettings, checkout ] }
and so on.
But then that would involve updating this document every time the user did something. Since elasticsearch writes a new record rather than updating in place, that would involve a horrendous amount of rewriting, given that each user might do say 5000 events in a year, and spread across different days. Not to mention rewriting of the index?
Is there an idiomatic way I'm missing of accomplishing a database by user that can handle regular updates to each user, and buid indexes that allow for fast querying of that data by multiple criteria - eg users who have done eventA AND eventB AND eventC?
Many thanks for all your help!
You can use Kibana for Visualizing Data stored in Elasticsearch.
You can use this type of events itself:-
{ userid: Joe, event: homepage }
{ userid: Mike, event: homepage }
{ userid: Joe, event: productsPage }
{ userId: Joe, event: accountSettings }
{ userId: Joe, event: checkout }
etc
After storing your data in Elasticsearch, You can use Kibana and create visualizations specifying AND Filters over the event field.

Resources