Shopify API post one product in multiple collections - api

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

Related

How to efficiently retrieve a list of all collections a product belongs to in Shopify?

I want to create a CSV export of product data from a Shopify store. For each product I'm exporting data like the product name, price, image URL etc... In this export I also want to list, for each product, all the collections the product belongs to, preferably in the hierarchal order the collections appear in the site's navigation menu (e.g Men > Shirts > Red Shirts).
If my understanding of the API is correct, for each product I need to make a separate call to the Collect API to get a list of collections it belongs to then another call to the Collections API to get the handle of each collection. This sounds like a lot of API calls for each product.
Is there a more efficient way to do this?
Is there any way to figure out the aforementioned hierarchy of collections?
Unfortunately, as you pointed out, I don't think there is an efficient way of doing this because of the way that the Shopify API is structured. It does not permit collections to be queried from products, rather only products queried from collections. That is, one can't see what collections a product belongs to, but can see what products belong to a collection.
The ShopifyAPI::Collect or ShopifyAPI::Collection REST resource does not return Product variant information, which is needed to get the price information as per the requirements. Furthermore, ShopifyAPI::Collect is limited to custom collections only, and would not work for products in ShopifyAPI::SmartCollection's. For this reason I suggest using GraphQL instead of REST to get the information needed.
query ($collectionCursor: String, $productCursor: String){
collections(first: 1, after: $collectionCursor) {
edges {
cursor
node {
id
handle
products(first: 8, after: $productCursor){
edges{
cursor
node{
id
title
variants(first: 100){
edges{
node{
price
}
}
}
}
}
}
}
}
}
}
{
"collectionCursor": null,
"productCursor": null
}
The $productCursor variable can be used to iterate over all of the products in a collection and the $collectionCursor to iterate over all collections. Note that only the first 100 variants need to be queried since Shopify has a hard limit on 100 variants per product.
The same query can be used to iterate over ShopifyAPI::SmartCollection's.
Alternatively the same query using the REST API would look something like this in Ruby.
collections = ShopifyAPI::Collection.all # paginate
collection.each do |collection|
collection.products.each do |product|
product.title
# note the extra call the Product API to get varint info
ShopifyAPI::Product.find(product.id).variants.each do |varaint|
variant.price
end
end
end
I don't see any way to address the inefficiencies with the REST query, but you might be able to improve on the GraphQL queries by using Shopify's GraphQL Bulk Operations.

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
]

How to search multiple api services

I am developing a search engine with angular 2.
Therefore I use APIs from multiple platforms.
It works if I call the search function from every api service manually.
But is it possible to do the same foreach api service?
Every api service has the same function:
search (query: string): Observable<Array<SearchResult>> { ... }
In the UI I want to separate the results by tabs.
Therefore every api service has a title:
public title: string = "the title";
For storing the search results locally I have a class that is extended by every api service. This class has helper functions etc.
Depending on the behaviour you need you can use merge, concat or forkJoin to merge multiple streams into one.
The code would look pretty much the same.
For example using merge in order to merge 2 streams into one.
If you have a list of apis you need to call for the search. Your code would look like this.
let apis: string[] = [];
let observables = apis.map(api => search(api)); // get an array of observables
let merged = observables.reduce((previous, current) => previous.merge(current), new EmptyObservable()); // merge all obserbable in the list into one.
merged.subscribe(res => doSomething(res));
This article might be helpful.

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.