How to efficiently retrieve a list of all collections a product belongs to in Shopify? - 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.

Related

Wix Corvid database connection with online Store Products and Collections

Lets say I need to have some logic in this use case scenario. The user is on the WIX Online Store's Product page for a particular product and clicks on QTY to order more units of the product. The logic to add is to check against the inventory at that moment and send a Twilio SMS message to the Store owner as a warning(this use case is somewhat contrived).
The thing is I dont seem to see any examples on WIX online training that shows how the Corvid Database can be connected to existing WIX Online stores which have Products and Collections already defined (which I assume is kept in some database). How does the Corvid Database and the Online Store Products/Collections map and how is it done and how can Corvid js code access that ? By the way, the Corvid uses the term "Collections" which does not seem related to Product Collections which must be a source of confusion for many.
You can access your Wix-Stores products collection using the wix-data module.
import wixStoresBackend from 'wix-stores-backend'; // Not needed here but try in the editor
import wixData from 'wix-data';
const WIX_STORES_PRODUCT_TABLE = 'Stores/Products';
const getProducts = () => {
return wixData.query(WIX_STORES_PRODUCT_TABLE)
.find()
.then((data) => {
let wixInventory = data.items;
return wixInventory
}
If you start there you will see all the items in your Wix-Stores. You can further query the database/collection by narrowing down the query. There are some good starter examples in the Corvid documentation for query here.
Just as a note - Because the Wix-Stores collections are read only you can query them but you can't write to them. If you have a look at wixStoresBackend within the Corvid editor the code completion there shows that you can update some parameters of a product however, you will need to modify a product's item if you want to adjust things like quantity.

Naming REST API - Get collections of non-member attributes

Let's say that I'm developing an application about shopping. I have defined the following endpoints, which are quite self-explanatory:
GET /items
GET /items/{item-id}
GET /stores
GET /stores/{store-id}
Now, I want to create another endpoint that displays the price of individual item at different stores. This price information is not included in /items/{item-id} since I don't think it's suitable to be an attribute of item, and getting the list of prices requires a bit more calculation as I cannot return the object directly. I will name the endpoint /items/{item-id}/prices and expect a response like this:
[
{
"store_id": "store_1",
"price": 13.00
},
{
"store_id": "store_2",
"price": 12.99
}
]
I want to extend this further and create another endpoint that returns the price information for all items, but I'm having trouble naming this endpoint. So far I've thought of /items/prices or /items?display=prices but the former might be confusing as it matches with /items/{item-id}, and the latter just.. does not seem to make sense for me.
What is the best name to pick for my endpoint so that it stays consistent with the convention?
For all items pricelist endpoint for a single store, I'd recommend GET /stores/{store-id}/prices or GET /stores/{store-id}/pricelist.
For all items/stores pricelist, I'd use GET /items/pricelist or GET /items/*/pricelist, (both special before /items/{item-id}), which could be store-specified on demand by ?store={store-id}.
Adding prices endpoint to items would make no sense as item itself has nothing to do. It is store's responsibility to dictate the price.
I would suggest renaming stores endpoint to /stores/description/{id} and adding prices subcategory /stores/prices/by-item/{id} and /stores/prices/by-store/{id}.
I would say that for sepecfic item /prices/{store-id}/{item-id}
and for all prices /prices/{store-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
}
}
}

Bigcommerce API - Create Shipment - Include all Items

according to the documentation, the Create Shipment method requires the property "items" - an array of the items being shipped, for example:
{
"tracking_number": "EJ958083578US",
"comments": "Ready to go...",
"order_address_id": 1,
"items": [
{
"order_product_id": 15,
"quantity": 2
}
]
}
In our business, a shipment almost invariably contains ALL items from the relevant order.
That being the case, is there a way to create a shipment without listing all items (which would require iterating over the product line-items)? Or, alternatively, a way to include all items by default (without iterating)?
We are simply wishing to automate the process of adding tracking numbers to orders - which (as a manual process) involves uploading a csv with [order_number: tracking_number] - i.e. it self-evidently assumes that all items are being shipped. The API seems not to include that (very sensible) option, but I may be wrong.
From Bigcommerce Support:
There is not a way to add a tracking number without adding a shipment nor a way to default the shipment to include all products. This is a helpful suggestion though that I will be passing on to our Product Team for possible implementation into future versions of the API.
Unfortunately for now it is necessary that you GET to the products subresource of an order and iterate over all of the products to pull their 'id' values and 'order_address_id' values so you can generate your POST request to the shipment subresource. It is not necessary to make a GET request to the shipping address subresource directly unless you want the details of that shipping address. It is also not necessary to make a GET request to the base order object unless you want details found there or you are looking to automate the process of checking for orders ready to ship.
So assuming you know an order ID that you want to ship it should only take 2 requests total to both GET the products subresource and then POST to the shipment resource.

Where to expose the results of a specific SQL query in the domain model

Which of these examples would be the best way to expose a collection of Orders for a specific Person that contain a specific Product and why? Or maybe there is a better way to do this alltogether? (Sorry I am new to domain modeling). The Orders list is pulled from the database with an SQL query and turned into a List collection.
A Person has 1 to many Orders and an Order has 1 to many Products.
1)
class Person
{
List OrdersContaining(Product p)
{.....}
}
2)
class Order
{
List ForPersonContainingProduct(Person person, Product product)
{.....}
}
2)
class Product
{
List OrdersFor(Person p)
{.....}
}
I would not expose such a method directly on the domain object itself, which encapsulates the data. Rather, I would use the DAO pattern applied to the Order domain. Which, in essence, is a variation of your #2:
class OrderDAO {
List<Order> listByPersonAndProduct(Person person, Product product){
.....
}
}
This way, the various patterns of access that you need to add over time are separated from the Order domain object.
Person could still have a .Orders collection which has all their orders. Then it becomes a question of lazy loading an populating this collection when you know you're going to need it. Something like N/Hibernate helps a lot here.