How to delete multiple items with GraphQL? - datatables

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.

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.

Need advices on multiple query Amplify QraphQL

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}
}
`)
);

How do I filter fields with Directus

Let's say I make an api call like this
const { data } = await client.getItems(`module/${module.id}`, {
fields: [
'questions.module_question_id.question_text',
'questions.module_question_id.slug',
'questions.module_question_id.type',
'questions.module_question_id.answer_options.*',
],
});
I am grabbing the fields, but I also want to filter out a certain question ala its slug, is there a way to do this at the api level? I know filters exist as a global query api, but have not found examples of them being used in conjunction with fields.
Perhaps you are looking for deep? This should allow you to filter on a deeply nested relational field.
https://docs.directus.io/reference/api/query/#deep

Merging data from different graphql resolvers in vue.js client side for simple outputting

I do query cars from an api with a single query but two resolvers (listing and listings)(hopefully resolver is the right name for it). One car I get by the id via listing and the other cars I get without filters by listings. The resolvers output the data i a little different structure on the server-side but I do get the same fields just at different „places“. I want to merge the structure in order to get a single array I can simply loop over in vue.js. For the apicalls I do use vue-apollo.
Couldn't find any information to merge data client-side inside graphqlqueries. All I found is about handling it serverside with resolvers but it's an api I do not own.
Is it possible with graphql or do I have to merge it inside my vuecomponent and if so what would be the best way to do so?
The output will be a grid of cars where I show the car of the week (requested by id) together with the newest cars of the regarding cardealer.
Full screenshot including response: https://i.imgur.com/gkCZczY.png
Stripped down example with just the id to show the problem:
query CarTeaser ($guid: String! $withVehicleDetails: Boolean!) {
search {
listing(guid: $guid){
details{
identifier{
id #for example: here I get the id under details->identifier
}
}
}
listings( metadata: { size: 2 sort:{ field: Age order: Asc}}) {
listings{
id #here it's right under listings
details{
…
}
}
}
}
}
}
Ideally you're right, it should be handled server-side, but if it's not your API the only solution is to manipulate the data on the client side, meaning in your component.
It's probably a lot simpler to leave the listings array untouched and to just merge the listing element with it, like this for instance:
// assuming 'search' holds the entire data queried from the api
const fullListing = [
// car of the week, data reformatted to have an identical structure as
// the 'other' cars
{
id: search.listing.details.identifier.id,
details: {
vehicle: search.listing.details.vehicle,
},
},
...search.listings.listings, // the 'other' cars
]

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
}
}
}