Discuss and resolve questions on Liquid, JavaScript, themes, sales channels, and site speed enhancements.
I want to create a list of all values of a metafield that products in a collection have. For this particular example, the metafield is named Model. I am trying to make a list of all the Models that are in this collection.
Based on Shopify Liquid documentation of arrays (https://shopify.dev/docs/api/liquid/filters/array-filters), it should be possible to use the filter map to get this with one line of code, like this:
{%- assign models_list = collection.products | map: 'metafields.custom.model' -%}
<p>{{ models_list | join: ', ' }}</p>
However, that is not working. I am getting a list of spaces separated by commas instead of the values of the metafield.
Using a for loop I can get the values successfully:
Solved! Go to the solution
This is an accepted solution.
However, you can chain several maps and it will work, not sure if it will be more efficient then a loop though:
{% assign list = collection.products | map: 'metafields' | map: 'custom' | map: 'model' %}
Still, keep in mind that big arrays like collection.products are paginated in Shopify, so you would not be accessing all collection products this way -- only the first 50-ish products.
If I remember properly, you can't use nested properties in map, so this would not work
collection.products | map: 'metafields.custom.model'
while this will:
collection.products | map: 'price'
Also, keep int mind that big arrays like collection.products are paginated in Shopify, so you would only be accessing first 50'ish products.
This is an accepted solution.
However, you can chain several maps and it will work, not sure if it will be more efficient then a loop though:
{% assign list = collection.products | map: 'metafields' | map: 'custom' | map: 'model' %}
Still, keep in mind that big arrays like collection.products are paginated in Shopify, so you would not be accessing all collection products this way -- only the first 50-ish products.
Yes, chaining multiple map filters like this:
{% assign list = collection.products | map: 'metafields' | map: 'custom' | map: 'model' %}
can work for extracting nested metafield values, but it’s not necessarily more efficient than a loop.
Key Considerations:
Pagination Limitation – Shopify limits collection.products to around 50 products per page, so this method won’t capture all products in large collections.
Handling Empty Values – Some products may not have the model metafield, leading to nil values in the array. Filtering out empty values might be necessary:
{% assign list = list | compact | uniq %}
Performance – If you have less than 50 products, map chaining is cleaner. But for large collections, a loop with pagination handling is more reliable.
Best Practice: If working with large collections, use a loop to ensure all products are processed across pages!
Sounds like you just fed Tim's comments to ChatGPT?
Brilliant!
I did a quick test as follows and it worked as expected. I added the 'uniq' filter:
{% assign models_list = collection.products | map: 'metafields' | map: 'custom' | map: 'model' | uniq %}
<p>{{models_list | join: ', '}}</p>
I checked 3 collections with <50 products and it got all the models each time. I checked on a collection that has more than 50 products and it only got some of the models, as expected, so I can confirm there is a limit here. My collections do mostly have less than 50 parent products (with multiple variants per parent product), so this should work for those cases.
Certain array functionalities in Shopify don't support dot notation. Most of the useful functional filters do not support dot notation, although sorting (sort, sort_natural etc.) does support it.
It has been suggested previously that this is a limitation of Liquid's implementation of these methods in Ruby.
You're correct that map should work in theory, but the issue likely arises from the way Shopify handles metafields. Here’s why:
Why map Isn't Working:
Metafield Access Issue: Shopify’s map filter works with direct properties of objects but can struggle with nested attributes like metafields. Since metafields.custom.model isn't a direct property of product but a nested attribute, map may return nil or an empty value.
Metafield Data Type: If metafields.custom.model is not a simple string but a json_string or another complex type, map may not extract it correctly.
Empty or Undefined Values: If some products don’t have the model metafield set, map might return an array with empty values, which could explain why you see spaces separated by commas.
Solution:
Since the for-loop method works, you can slightly optimize it while ensuring unique values:
{%- assign models_list = "" -%}
{%- for product in collection.products -%}
{%- if product.metafields.custom.model != blank -%}
{%- assign models_list = models_list | append: product.metafields.custom.model | append: "," -%}
{%- endif -%}
{%- endfor -%}
{%- assign models_list = models_list | split: "," | uniq | sort -%}
<h3>Models List: {{ models_list | join: ', ' }}</h3>
Why This Works:
Checks for blank values to avoid adding empty metafields.
Appends each model to a string before splitting it into an array.
Uses uniq and sort to remove duplicates and organize the list.
Unfortunately, until Shopify enhances Liquid’s handling of metafields, map isn’t always reliable for metafields. There're more information
Learn how to build powerful custom workflows in Shopify Flow with expert guidance from ...
By Jacqui May 7, 2025Did You Know? May is named after Maia, the Roman goddess of growth and flourishing! ...
By JasonH May 2, 2025Discover opportunities to improve SEO with new guidance available from Shopify’s growth...
By Jacqui May 1, 2025