Need advices on multiple query Amplify QraphQL - api

I am developping an application using AWS Amplify.
I am using the Graphql API to manage my Dynamodb tables.
I need some advices to know the best way to mutate multiple Items in a table.
I read that Qraphql and dynamodb are able to mutate 1000 items per second, but actualy this performance is not working on my way :(.
To mutate multiple items i have an array with all my queries and input parameters, and i am using Promise.all function like :
await Promise.all(
options.data.map( item =>
API.graphql(
graphqlOperation(
item.query,
{ input: item.input }
)
)
)
);
Is it the good way to do that ? it's working but with 1000 items it tooks 4/5 seconds.
Could you advice me how to improve the performance of multiple item mutation using Amplify graphQl API ?
Thank you very much

Try sending all your queries or mutations with 1 request instead of using API.graphql multiple times.
For example this how I delete the post's comments when I delete the post.
const commentMutations: any = comments.map(
(comment: Comment, i: number) => {
return `mutation${i}: deleteComment(input: {id: "${comment.id}"}) { id }`;
}
);
await API.graphql(
graphqlOperation(`
mutation deletePostComments {
${commentMutations}
}
`)
);

Related

How many SQL database calls are made when you do a deeply nested GraphQL query?

I know with GraphQL you are to implement the backend handlers for the queries. So if you are using PostgreSQL, you might have a query like this:
query {
authors {
id
name
posts {
id
title
comments {
id
body
author {
id
name
}
}
}
}
}
The naive solution would be to do something like this:
const resolvers = {
Query: {
authors: () => {
// somewhat realistic sql pseudocode
return knex('authors').select('*')
},
},
Author: {
posts: (author) => {
return knex('posts').where('author_id', author.id)
},
},
Post: {
comments: (post) => {
return knex('comments').where('post_id', post.id)
},
},
};
However, this would be a pretty big problem. It would do the following essentially:
Make 1 query for all authors.
For each authors, make query for all posts. (n + 1 query)
For each post, make query for all comments. (n + 1 query)
So it's like a fanning out of queries. If there were 20 authors, each with 20 posts, that would be 21 db calls. If each post had 20 comments, that would be 401 db calls! 20 authors resolves 400 posts, which resolves 8000 comments, not like this is a real way you would do it, but to demonstrate the point. 1 -> 20 -> 400 db calls.
If we add the comments.author calls, that's another 8000 db calls (one for each comment)!
How would you batch this into let's say 3 db calls (1 for each type)? Is that what optimized GraphQL query resolvers do essentially? Or what is the best that can be done for this situation?
This is the GraphQL N+1 loading issue.
Basically there are two ways to solve it (For simplicity , assume it only needs to load the authors and its posts)
Use Dataloader pattern. Basically its idea is to defer the actual loading time of the posts of each author to a particular time such that the posts for N authors can be batched loaded together by a single SQL. It also provides caching feature to further improve the performance for the same request.
Use "look ahead pattern" (A Java example is described at here) . Basically its idea is that when resolving the authors , you just look ahead to see if the query includeS the posts or not in the sub fields. If yes , you can then use a SQL join to get the authors together with its post in a single SQL.
Also , to prevent the malicious client from making a request that retrieve a very big graph , some GraphQL server will analyse the query and impose a depth limit on it.

How to attach multiple parameters to an API request?

I built my own simple REST API with Express and now I'm consuming it from my client (Vue.js)
So in my page I access all the data from this endpoint: GET /api/books, and it works fine
Now I also have a "sort by" button where I want to get the data by the latest entries. I don't know if that's a good way or if I have to handle this in the backend but what I do is calling the same endpoint which is GET /api/books and sorting the data to get them the right way
For ex:
sortByLatest() {
axios
.get("/api/books")
.then(res => {
const books = res.data;
const sortedBooks = books.sort((a, b) => b.createdAt > a.createdAt ? 1 : -1
);
this.books = sortedBooks;
})
// catch block
}
I do that for everything. If I need a limited number of results or a specific property from the data I have to write some logic in the axios .then block to sort or filter what I want. Is this bad practice?
But that's not my actual problem
My problem is, in addition of sorting by the latest entries, I also want to filter the results by a specific property. The problem is when I click the A button it's gonna filter the books by a specific property, and when I click the B button it's gonna sort them buy the latest entries, but not both at the same time!
And what if I want additionnal things like limit the number of results to 10, filter by other properties etc... I want to be able to create requests that ask all those things at once. How can I do that? Do I have to build that in the backend?
I saw some websites using url parameters to filter stuff, like /genre=horror&sort=latest, is that the key of doing it?
Thank you for your time

Podio API JS - Update relationship field of a Item

Using NodeJS, I am trying to update relationship field which link to another app (contacts-leads). I have try all combination but still getting error. I think I have the necessary data to post, app_id, item_id, external_id..etc. I need help with forming JSON structure.
p.request('put','item/<Item_Id>/value', data)
var data {....}
app_id:'<app_id>'
value:'<value>' (value is the app_item_id of the link to application; that is the number in URL)
app_item_id: '<app_item_id>'
external_id:'<external_id>'
I was able to update non-relationship field without problem.
Thanks
Well, going to answer my own question. That will work for single app link, not sure about multiple ones.
data = {
"<external_id>": {
"apps": [{"app_id": <app_id>}],
"value: <app_item_id>
}
}

Shopify API post one product in multiple collections

we're managing a marketplace in Shopify, and we're doing a lot of calls. We'd like to improve the number of calls and one of the keypoints is when we introduce the product in collections. One product can be inserted in multiple collections, and we do this for each post/collection:
public function pushCollection($shopifyProductId, $collectionId)
{
$collectData = [
"product_id" => $shopifyProductId,
"collection_id" => $collectionId
];
$this->client->Collect()->post($collectData);
return;
}
The question is, is there any way to post 1 product in multiple collections with a single call?
Thank you so much
You cannot do that. But if you can accumulate products to add to collections you can add multiple products to a collection in a single call.
see https://help.shopify.com/api/reference/customcollection#update
I am a little late to answer but you can add one product to multiple collections in a single API call using Shopify's GraphQL API. Here's the documentation on it: https://help.shopify.com/en/api/graphql-admin-api/reference/mutation/productcreate
The GraphQL API call to add an already existing product to already existing multiple collections would look something like this:
mutation {
productUpdate( input:
{
$id:"gid://shopify/Product/{shopifyProductId}"
collectionsToJoin:["gid://shopify/Collection/{collectionId1}","gid://shopify/Collection/{collectionId2}" ]
})
{
product{
id
}
}
}

How to delete multiple items with GraphQL?

I am new in GraphQL.
How can I write a delete mutation to delete multiple items (more than one ID) in GraphQL?
I use scaphold.io.
You can batch multiple mutations in the same request to the GraphQL server using GraphQL aliases.
Let's say this is how you delete one Item:
mutation deleteOne {
deleteItem(id: "id1") {
id
}
}
Then this is how you can delete multiple items in one request:
mutation deleteMultiple {
id1: deleteItem(id: "id1") {
id
}
id2: deleteItem(id: "id2") {
id
}
# ... and so on
id100: deleteItem(id: "id100") {
id
}
}
It's helpful to know that multiple mutations in one request run sequentially in the stated order (from top to bottom). You can also run multiple queries in one request the same way, and multiple queries in one request run in parellel.
If you want to run say 1000 mutations, it might be better to batch them in 10 groups of 100.
More information and another example can be found in this FAQ article as well as the official GraphQL docs.
I think that good solution would be to create a method (mutation) that accepts array of e.g. IDs, that are further used to batch delete multiple records from the database.
mutation deleteUsers($userIds: [Int!]!) {
deleteUsers(userIds: $userIds) {
...
}
}
Then, in the resolver you could use the userIds parameter to perform an SQL query like DELETE FROM users WHERE id IN userIds, where userIds of course should be correctly replaced (escaped), depending on how you interact with the database.