Need ability to query `z.array()` fields (e.g. tags) in the latest nuxt-content module (v3.alpha.8)
Discussed in https://github.com/nuxt/content/discussions/2955
Originally posted by humblemodulo January 7, 2025 In the previous version of nuxt-content (v2) I would simply query tags like so:
.where({ tags: { $contains: tagSlug } })
However there is no contains in v3, and the logic for IN seems to require the reverse operation. I've tried LIKE and that doesn't work either.
Definitely need to know the best way to find values in z.array() field types.
As it stands, I'm forced to retrieve all, then run JS .filter() on the results. Quite inefficient.
Could you provide a simple reproduction?
The proper way to do this in sqlite is using json_each operator, which is not yet supported in Content query builder.
However, I believe we can achieve your goal with simpler solution with LIKE. If you provide a simple reproduction we can sort it out.
.where('tags', 'LIKE', `%${route.params.tag}%`)
I believe I've run into the same problem as @humblemodulo - the above use of LIKE solved my problem but here's a repo demonstrating the issue: https://github.com/terrarum/nuxt-in-tag-repro
app.vue contains the example and the above solution, but with this schema definition:
schema: z.object({
tags: z.array(z.string()).default([]),
})
and this frontmatter:
---
tags:
- show
- tag1
---
I expected to be able to filter posts like so:
return queryCollection('blog')
.where('tags', 'IN', 'show')
.all()
But instead it returns nothing.
Have the same issue as @terrarum and @humblemodulo
I have updated my reproduction repo above to @nuxt/content v3.1.0. The problem persists, as do the horrors.
facing a similar issue, as I have a custom slug defined which is now part of the meta object. I can't use the .path() method because I do not want to rely on the file name as route slug.
However I haven't found a way to access the slug in the query. Using .where("meta.slug","=",mySlug) was my first assumption, but not working.
So using like solves it, but I'd which there would be a cleaner approach in the future Thanks @UphkcRNqmafQWcSSSSSS for the tip
It would be nice to have this: .where('tags', 'LIKE',%${route.params.tag}%) be documented because as of now there is absolutely nothing in docs saying that .where('tags', 'IN', route.params.tag) doesn't work with arrays and thus it brings a lot of confusion and leaves users without any feedback regarding such use case.
I run debugger on @nuxt/content code and executing a query for retrieving articles with a given tag (tags is an array) returns an error as if the field and value from the internal function where changed:
In my case on article I have a front matter with the following fields:
---
title: Blog Post 1
date: 2025-03-31
tags: [Vue, Nuxt, CSS]
category: Security
---
So according to content docs executing .where('tags', 'IN', 'Vue') should return this article from above.
I would suggest using .where('tags', 'LIKE', '%"tagName"%') for now.
If I'm not mistaken, the tags array (z.array(z.string())) is serialized into a string like ["tag1","tag2"] in the database. Since the where function constructs a LIKE query, using '%car%' as a pattern would incorrectly match substrings (e.g., "carpet", % represents "zero, one, or multiple characters"). To ensure an exact match for a tag within the serialized array, the search pattern must include the quotes, like .where('tags', 'LIKE', '%"car"%').
I was able to filter by selected tags using this construction:
.orWhere((groupFactory) => selectedTags.reduce(
(gf, tag) => gf.orWhere(
g => g.where('tags', 'LIKE', `%"${tag}"%`)
), groupFactory)
)