Our Partner & Developer boards on the community are moving to a brand new home: the .dev community forums! While you can still access past discussions here, for all your future app and storefront building questions, head over to the new forums.

Re: How can I access multiple discountNodes Metafields value?

How can I access multiple discountNodes Metafields value?

yedla_dinesh
Shopify Partner
11 0 2

Hi everyone, 

 

I am attempting to create multiple discounts using the 'discountAutomaticAppCreate' GraphQL function and add metafields with the same key and namespace. This process has been successful and I have created 2 automatic discount. However, when I try to access the metafield in the 'run.graphql' file, I only retrieve the metafield of the latest discount node.

Therefore, my question is: How can I access the metafields of multiple discount nodes?

Is I'm missing somthing? Please help with me out with some clarification.
@Nick_Wesselman @Liam @SomeUsernameHe 


Kindly check the below code.

 

query RunInput($selectedCollectionIds: [ID!]) {
  cart {
    lines {
      quantity
      merchandise {
        __typename
        ... on ProductVariant {
          id
          product {
            id
            inAnyCollection(ids: $selectedCollectionIds)
          }
        }
      }
    }
  }
  discountNode {
    metafield(
      key: "test-function-config"
      namespace: "test-discount"
    ) {
      value
    }
  }
}

 


Thanks

Shopify Expert
Helping thousands of @Shopify store owners to achieve sustainable growth & increase revenue 2-3x 
Replies 20 (20)

SomeUsernameHe
Shopify Partner
517 57 110

To access the metafields of multiple discount nodes in Shopify using GraphQL, you need to modify your query to include each discount node you're interested in. From the provided query, it seems you're trying to access a single metafield from a generic discountNode which would typically return the metafield from the latest or default discount node.

To fetch metafields from multiple discounts, you must query each discount node separately. Here's how you can modify your query to retrieve the metafields from multiple discount nodes by specifying their IDs:

 

 

query GetDiscountMetafields($discountIds: [ID!]!) {
nodes(ids: $discountIds) {
... on DiscountNode {
id
metafield(namespace: "test-discount", key: "test-function-config") {
value
}
}
}
}

 

In this modified query, you provide a list of discount IDs as an input variable $discountIds. The query uses these IDs to fetch the metafield for each DiscountNode. This approach allows you to access the metafields of each discount individually based on the IDs you specify.

 

Assuming you know the specific IDs of the discounts whose metafields you want to access, you can pass them in the query like this:

 

{
"discountIds": ["gid://shopify/DiscountNode/1234567890", "gid://shopify/DiscountNode/0987654321"]
}

 

This method ensures that you retrieve the metafields from all specified discounts, allowing for more precise control over which discounts' metafields are accessed

 

Sorry, was not able to test this code completely since I am heading to bed, but if you still need help with it I'm a bit, I will troubleshoot when I wake up 

Have I helped? Consider putting coffee in my mouth!
Buy Me a Coffee
Nick_Wesselman
Shopify Staff
171 43 71

The question is about Functions, not the Admin API.

Nick Wesselman | Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit the Shopify Help Center or the Shopify Blog

Nick_Wesselman
Shopify Staff
171 43 71

Hi @yedla_dinesh --

 

I may not understand your goals fully, but in a given function execution, you can only obtain the metafields for a single discount. You can reuse the same functionId across multiple discounts, and they should both execute independently and in parallel, with their own metafields. They may not both apply to the cart, depending on the discount combination rules.

 

-Nick

Nick Wesselman | Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit the Shopify Help Center or the Shopify Blog

yedla_dinesh
Shopify Partner
11 0 2

Thanks for your reply.

I understand that in a single function execution, I can only obtain the metafields for a single discount. However, I want to access the metafields for multiple discounts in one go.

Let's say I've created 2-3 discounts using the 'discountAutomaticAppCreate' GraphQL function (and I've also added metafield data to each discount). Now, can I access all the discount metafield values in the Shopify product discount function (run.graphql) input query?

I really appreciate your help!

Thanks

 

Shopify Expert
Helping thousands of @Shopify store owners to achieve sustainable growth & increase revenue 2-3x 
Nick_Wesselman
Shopify Staff
171 43 71

Hi @yedla_dinesh --

No, this is not possible. Each discount you create with discountAutomaticAppCreate represents a separate execution of your function. They will all be executed in parallel and the discounts will be combined according to Shopify's discount combination rules. Each execution can only access the metafields of a single discount.

 

If you are looking for some sort of shared configuration, you might consider a shop metafield. Otherwise the best practice is to configure and output the discounts independently from each function run, and allow Shopify to choose the best discount combination for the shopper.

 

-Nick

Nick Wesselman | Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit the Shopify Help Center or the Shopify Blog

Codesto1
Shopify Partner
41 3 5

In the same example suppose multiple discounts are created how can I pass a discount id to the run.graphql query?

query RunInput {
  discountNode {
    metafield(namespace: "can I make dynamic and have it use the discount id?", key: "function-configuration") {
      value
    }
  }
}

 

SomeUsernameHe
Shopify Partner
517 57 110

https://shopify.dev/docs/apps/build/functions/input-output/use-variables-input-queries

You pass everything to run.graphql through input variables. 

Have I helped? Consider putting coffee in my mouth!
Buy Me a Coffee
Codesto1
Shopify Partner
41 3 5

Thank you! The documentation is slightly confusing.  In Step 2 it says to create the fields in metafield-values.json

But then below it says to set them in set-metafield.graphql mutation.  

Then in step 3 it says to load them via the extensions toml like so:

[extensions.input.variables]
namespace = "$app:my-namespace"
key = "my-key"

 What is the purpose of the metafield-values.json if they have to be manually set in the set metafield?

SomeUsernameHe
Shopify Partner
517 57 110

Yeah, that can be a little confusing. 

metafield-values.json is not something you create. The box referencing metafield-values.json is just showing you how your values should look when saving them with the "mutation SetMetafield"

 

mutation SetMetafield {
  metafieldsSet(metafields: [
    {
      namespace: "$app:my-namespace",
      key: "my-key",
      ownerId: "OWNER_ID",
      type: "json",
      value: "{\"excludedCollectionIds\"=>[\"gid://shopify/Collection/1\", \"gid://shopify/Collection/2\", \"gid://shopify/Collection/3\"], \"vipCollectionIds\"=>[\"gid://shopify/Collection/4\", \"gid://shopify/Collection/5\"]}{\"selectedCollectionIds\":[\"gid://shopify/Collection/1\",\"gid://shopify/Collection/2\",\"gid://shopify/Collection/3\"]}"
    }
  ]) {
    metafields {
      id
    }
  }
}

 



Have I helped? Consider putting coffee in my mouth!
Buy Me a Coffee
Codesto1
Shopify Partner
41 3 5

Ok got it.  Suppose I have one function but I have multiple discounts.  (As stated above originally in the first question) is there away I can make the name space dynamic? Currently the way it looks there's no dynamic way to look up data.  Dynamic in this context would be just me setting the variable fields but how would I be able to have it actually run the dynamic data when the function runs?

SomeUsernameHe
Shopify Partner
517 57 110

I am not quite sure I understand what you are asking. 

"no dynamic way to look up data" That is what you are doing with graphql.run. That is the entire point of graphql.run is that is runs and pulls all relevant information you need for run.js to run and apply the discount. 


Have I helped? Consider putting coffee in my mouth!
Buy Me a Coffee
Codesto1
Shopify Partner
41 3 5

I'm sorry I didn't explain it correctly.  Here is what I mean.  I have one function called product-discount.

This function creates a discount.  Suppose the function creates:

Discount1, Discount2, Discount3 

Each one of these discounts gives a discount based on a product tag.  

In the run.graphql I have 

query RunInput($prodTags: [String!]) {
  cart {
    lines {
      id
      quantity
      merchandise {
        ... on ProductVariant {
          id
          product {
            hasAnyTag(tags: [$prodTags])
          }
        }
        __typename
      }
    }
  }
}

 But how could I actually pass a product tag to run.graphql? I could manually input it but I need it to be dynamic because there are multiple discounts.  Is this even possible?

SomeUsernameHe
Shopify Partner
517 57 110

So here is how I pass tags to my product discount functinon. 

Here is my graphql.run:

 

query Input($selectedCollectionIds: [ID!], $tags: [String!]) {
  cart {
    lines {
      merchandise {
        __typename
        ... on ProductVariant {
          id
          product {
            handle
            inCollections(ids: $selectedCollectionIds) {
              collectionId
              isMember
            }
          }
        }
      }
    }
    buyerIdentity {
      customer {
        hasTags(tags: $tags) {
          tag
          hasTag
        }
      }
    }
  }
  shop {
    metafield(namespace: "simplewholesale", key: "tags") {
      value
    }
  }
}

 


In this code, I pass my "tags" that I use for discounts with:

 

 hasTags(tags: $tags)

 


This looks in the metafield we created earlier:

 

mutation SetMetafield {
  metafieldsSet(metafields: [
    {
      namespace: "$app:my-namespace",
      key: "my-key",
      ownerId: "OWNER_ID",
      type: "json",
      value: "{\"excludedCollectionIds\"=>[\"gid://shopify/Collection/1\", \"gid://shopify/Collection/2\", \"gid://shopify/Collection/3\"], \"vipCollectionIds\"=>[\"gid://shopify/Collection/4\", \"gid://shopify/Collection/5\"]}{\"selectedCollectionIds\":[\"gid://shopify/Collection/1\",\"gid://shopify/Collection/2\",\"gid://shopify/Collection/3\"]}"
    }
  ]) {
    metafields {
      id
    }
  }
}

 


Which for my discount has something like this: 

 

{
  "selectedCollectionIds": [
    "gid://shopify/Collection/310827712556"
  ],
  "tags": [
    "Pro",
    "VIP"
  ]
}

 


^ So in this metafield is where I save all of my "dynamic content" for my graphql. Then in run.graphql you can call a specific "selectedCollectionIds" or "tags" by selecting the variable you want to use, in my case it will be "id" then the option name in your metafield which will be "selectedCollectionIds" and the code will look like this: 

 

ids: $selectedCollectionIds

 


Now, 

inCollections(ids: $selectedCollectionIds) will compare with all of my collections under selectedCollectionIds in the metafield. 

and the same goes for 

 

hasTags(tags: $tags)

 

Have I helped? Consider putting coffee in my mouth!
Buy Me a Coffee
SomeUsernameHe
Shopify Partner
517 57 110

I had AI reword my reply a little more technical since I am in a little bit of a rush, but this should be a little more clear:

In my Shopify Product Discount Function, I dynamically pass tags and collection IDs to apply discounts based on customer tags and product collections. Here’s how the process works using GraphQL queries and Shopify Metafields:

1. GraphQL Query (graphql.run)

I use the following GraphQL query to retrieve information about the products in the cart, as well as the tags associated with the customer:

 

 

query Input($selectedCollectionIds: [ID!], $tags: [String!]) {
  cart {
    lines {
      merchandise {
        __typename
        ... on ProductVariant {
          id
          product {
            handle
            inCollections(ids: $selectedCollectionIds) {
              collectionId
              isMember
            }
          }
        }
      }
    }
    buyerIdentity {
      customer {
        hasTags(tags: $tags) {
          tag
          hasTag
        }
      }
    }
  }
  shop {
    metafield(namespace: "simplewholesale", key: "tags") {
      value
    }
  }
}

 

 

Breakdown:

  • inCollections(ids: $selectedCollectionIds): This checks whether the products in the cart belong to any of the collections passed in the $selectedCollectionIds variable.
  • hasTags(tags: $tags): This checks if the customer has any of the tags specified in the $tags variable, which I pass to the function.

2. Dynamic Content Storage in Metafields

The dynamic values for the tags and collections used in the query are stored in a Shopify Metafield. Here’s an example of how I set the metafield using a GraphQL mutation:

 

 

mutation SetMetafield {
  metafieldsSet(metafields: [
    {
      namespace: "$app:my-namespace",
      key: "my-key",
      ownerId: "OWNER_ID",
      type: "json",
      value: "{\"selectedCollectionIds\":[\"gid://shopify/Collection/310827712556\"],\"tags\":[\"Pro\",\"VIP\"]}"
    }
  ]) {
    metafields {
      id
    }
  }
}

 

 

Metafield Structure:

The metafield stores the collections and tags in a JSON structure like this:

 

 

{
  "selectedCollectionIds": [
    "gid://shopify/Collection/310827712556"
  ],
  "tags": [
    "Pro",
    "VIP"
  ]
}

 

 

This JSON object is used to dynamically manage discount logic. The selectedCollectionIds array contains collection IDs that the product might belong to, and the tags array stores customer tags (like "Pro" and "VIP").

3. Querying Metafield Data in run.graphql

In my run.graphql query, I pass variables from the metafield data to dynamically check for product collections and customer tags. Specifically:

  • inCollections(ids: $selectedCollectionIds): This checks whether products in the cart are part of any of the collections in the selectedCollectionIds array from the metafield.

  • hasTags(tags: $tags): This checks if the customer has any of the tags specified in the tags array from the metafield.

Summary:

In this setup, the dynamic content (like collection IDs and customer tags) is stored in a metafield as a JSON object. I use that metafield to pass values to the GraphQL query for determining which collections a product belongs to and which tags a customer has. This allows the discount function to apply discounts based on the customer's tags and the product's collection membership.

This structure makes it easy to dynamically update the tags and collection IDs in the metafield without modifying the core function logic, ensuring flexibility in applying discounts.

Have I helped? Consider putting coffee in my mouth!
Buy Me a Coffee
Codesto1
Shopify Partner
41 3 5

SO AWESOME! THANK YOU!!!!

SomeUsernameHe
Shopify Partner
517 57 110

You are welcome! Happy coding!

Have I helped? Consider putting coffee in my mouth!
Buy Me a Coffee
Codesto1
Shopify Partner
41 3 5

Thank you for your amazing help I had one more question. How does run.graphql know to reference the metafields for the variables? 

in example:: 

query Input($selectedCollectionIds: [ID!], $tags: [String!]) {

Correct me if I'm wrong but would they be added to the shopify.extension.tom?

If so would it be:

      namespace = "$app:my-namespace",
      key = "my-key"
SomeUsernameHe
Shopify Partner
517 57 110

Of course, no problem. 

Correct, you would add the following to your shopify.extension.toml:

 

[extensions.input.variables]
namespace = "$app:my-namespace"
key = "my-key"

 

 
This references the metafield that run.graphql will check for selectedCollectionIds or tags per the example above. You can only have 1 here. So that is why you put everything you need in this one single metafield.

Have I helped? Consider putting coffee in my mouth!
Buy Me a Coffee
Codesto1
Shopify Partner
41 3 5

I had one more question so sorry! 

I'm passing this value (this is from graphql) "value": "{\"selectedCollectionIds\":[\"gid://shopify/Collection/310827712556\"],\"tags\":[\"CL Og test\",\"VIP234234\"]}"

When I run 

hasAnyTag(tags: $tags)
it always returns false. but I"m sure the tag is in the product.  Any idea why this happens? 
 

Codesto1
Shopify Partner
41 3 5

What was your solution or work around?