content icon indicating copy to clipboard operation
content copied to clipboard

Need ability to query `z.array()` fields (e.g. tags) in the latest nuxt-content module (v3.alpha.8)

Open humblemodulo opened this issue 11 months ago • 9 comments

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.

humblemodulo avatar Jan 10 '25 02:01 humblemodulo

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.

farnabaz avatar Jan 13 '25 09:01 farnabaz

 .where('tags', 'LIKE', `%${route.params.tag}%`)

UphkcRNqmafQWcSSSSSS avatar Jan 17 '25 12:01 UphkcRNqmafQWcSSSSSS

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.

terrarum avatar Jan 26 '25 23:01 terrarum

Have the same issue as @terrarum and @humblemodulo

brandsquare avatar Feb 01 '25 11:02 brandsquare

I have updated my reproduction repo above to @nuxt/content v3.1.0. The problem persists, as do the horrors.

terrarum avatar Feb 07 '25 08:02 terrarum

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

mklueh avatar Mar 09 '25 18:03 mklueh

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:

Image

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.

kwiat1990 avatar Apr 02 '25 20:04 kwiat1990

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"%').

SkyBird233 avatar Jun 25 '25 10:06 SkyBird233

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)
)

DudaevAR avatar Oct 12 '25 17:10 DudaevAR