Skip to main content

Listing Products

Products are listed when:

  • Displaying the contents of a collection
  • Displaying search results

In Vendure, we usually use the search query for both of these. The reason is that the search query is optimized for high performance, because it is backed by a dedicated search index. Other queries such as products or Collection.productVariants can also be used to fetch a list of products, but they need to perform much more complex database queries, and are therefore slower.

Listing products in a collection

Following on from the navigation example, let's assume that a customer has clicked on a collection item from the menu, and we want to display the products in that collection.

Typically, we will know the slug of the selected collection, so we can use the collection query to fetch the details of this collection:

query GetCollection($slug: String!) {
collection(slug: $slug) {
id
name
slug
description
featuredAsset {
id
preview
}
}
}

The collection data can be used to render the page header.

Next, we can use the search query to fetch the products in the collection:

query GetCollectionProducts($slug: String!, $skip: Int, $take: Int) {
search(
input: {
collectionSlug: $slug,
groupByProduct: true,
skip: $skip,
take: $take }
) {
totalItems
items {
productName
slug
productAsset {
id
preview
}
priceWithTax {
... on SinglePrice {
value
}
... on PriceRange {
min
max
}
}
currencyCode
}
}
}
note

The key thing to note here is that we are using the collectionSlug input to the search query. This ensures that the results all belong to the selected collection.

Here's a live demo of the above code in action:

The search query can also be used to perform a full-text search of the products in the catalog by passing the term input:

query SearchProducts($term: String!, $skip: Int, $take: Int) {
search(
input: {
term: $term,
groupByProduct: true,
skip: $skip,
take: $take }
) {
totalItems
items {
productName
slug
productAsset {
id
preview
}
priceWithTax {
... on SinglePrice {
value
}
... on PriceRange {
min
max
}
}
currencyCode
}
}
}
tip

You can also limit the full-text search to a specific collection by passing the collectionSlug or collectionId input.

The search query can also be used to perform faceted search. This is a powerful feature which allows customers to filter the results according to the facet values assigned to the products & variants.

By using the facetValues field, the search query will return a list of all the facet values which are present in the result set. This can be used to render a list of checkboxes or other UI elements which allow the customer to filter the results.

{
"term": "camera",
"skip": 0,
"take": 10
}

These facet values can then be used to filter the results by passing them to the facetValueFilters input

For example, let's filter the results to only include products which have the "Nikkon" brand. Based on our last request we know that there should be 2 such products, and that the facetValue.id for the "Nikkon" brand is 11.

{
"facetValue": {
"id": "11",
"name": "Nikkon",
"facet": {
"id": "2",
"name": "brand"
}
},
"count": 2
}

Here's how we can use this information to filter the results:

note

In the next example, rather than passing each individual variable (skip, take, term) as a separate argument, we are passing the entire SearchInput object as a variable. This allows us more flexibility in how we use the query, as we can easily add or remove properties from the input object without having to change the query itself.

{
"input": {
"term": "camera",
"skip": 0,
"take": 10,
"groupByProduct": true,
"facetValueFilters": [
{ "and": "11" }
]
}
}
info

The facetValueFilters input can be used to specify multiple filters, combining each with either and or or.

For example, to filter by both the "Camera" and "Nikkon" facet values, we would use:

{
"facetValueFilters": [
{ "and": "9" },
{ "and": "11" }
]
}

To filter by "Nikkon" or "Sony", we would use:

{
"facetValueFilters": [
{ "or": ["11", "15"] }
]
}

Here's a live example of faceted search. Try searching for terms like "shoe", "plant" or "ball".

Listing custom product data

If you have defined custom fields on the Product or ProductVariant entity, you might want to include these in the search results. With the DefaultSearchPlugin this is not possible, as this plugin is designed to be a minimal and simple search implementation.

Instead, you can use the ElasticsearchPlugin which provides advanced features which allow you to index custom data. The Elasticsearch plugin is designed as a drop-in replacement for the DefaultSearchPlugin, so you can simply swap out the plugins in your vendure-config.ts file.