content icon indicating copy to clipboard operation
content copied to clipboard

v2 -> v3: queryCollection().sort() unexpected order

Open chrisjansky opened this issue 10 months ago β€’ 6 comments

Environment

  • Operating System: Darwin
  • Node Version: v23.6.1
  • Nuxt Version: 3.15.4
  • CLI Version: 3.21.1
  • Nitro Version: 2.10.4
  • Package Manager: [email protected]
  • Builder: -
  • Runtime Modules: @nuxt/[email protected]

Version

v3

Reproduction

I would like to post a reproduction, but I am unable to setup @nuxt/content3 in StackBlitz: getting this error:

Restarting Nuxt due to error: `Error: Could not locate the bindings file. Tried:                                                                                     nuxi:nuxi 18:08:53
 β†’ /home/project/node_modules/better-sqlite3/build/better_sqlite3.node
...

Is there a workaround or a starter template that I am not seeing?

Description

Coming from v2, I am unable to reproduce the same JSON sorting and filtering behaviour.

Before (v2):

queryContent
      .where({ _type: "json", status: { $not: "hidden" } })
      .sort({ status: 1, priority: 1 })
      .find()

Expected result:

- one
  - status: something
  - priority: 1
- two
  - status: something
  - priority: 2
- three
  - status: null
  - priority: 2

Discarded:

- four
  - status: hidden <= // discarded because status = hidden
  - priority: null

After (v3):

queryCollection
      .andWhere((query) => query.where("extension", "=", "json").where("status", "<>", "hidden"))
      .order("status", "ASC")
      .order("priority", "ASC")

Actual result:

- bar
  - status: something
  - priority: 1
- baz
  - status: something
  - priority: 2

Namely item three discarded because status = null, but only status = hidden should be discarded.

Also in v2 it was possible to have a complex sorting query using multiple criteria, i.e. sort items with status first and then sort those based on priority.

I am missing something? πŸ˜…

Thanks!

Additional context

No response

Logs


chrisjansky avatar Jan 30 '25 17:01 chrisjansky

I'm confused about the issue, for me it's more like filtering than ordering. Content v3 uses Sqlite for filtering and Sqlite deals with null values a bit differently than v2. If you use <> operator in the query it will ignore null values.

You can use orWhere to resolve it, you can check the internal usage https://github.com/nuxt/content/blob/b46fc378019d77117e301e0099cf1ca0cd039c6f/src/runtime/internal/navigation.ts#L15-L18

As for StackBlitz, Just run this command and it will fix:

npm i https://pkg.pr.new/@nuxt/content@b46fc37 sqlite3

(better-sqlite3 does not support WebContainers and in current dev release Module detects WebContainer and uses sqlite3 package to resolve it)

farnabaz avatar Jan 31 '25 16:01 farnabaz

@farnabaz Thanks for the reply.

I understand the motivation behind migrating to SQLite, but the resulting new API is not very intuitive to use.

What was before a simple prefixing with dot to ignore a file: .ignoreMe.md (see #3090) has now become:

---
hidden: true
---
queryCollection("projects")
    .orWhere((query) => query.where("hidden", "<>", true).where("hidden", "IS NULL"))
    .all()

It’s unfortunate that one has to do these mental gymnastics in a compound filtering in order to filter a very simple use case: omit a particular value.

Also I have noticed a discrepancy:

projects: defineCollection({
      type: "page",
      source: "projects/*.md",
      schema: z.object({
        hidden: z.boolean().optional(),
      }),
    })

You quoted the source code with .where('navigation', '<>', 'false'), but it turns out queryCollection schema already unwraps the values and returns the parsed boolean, so it must be false boolean in query.where, not a string 😒

I know it’s absolutely pointless to be nagging about an open source project that you do in your free time. The reality is the migration is very painful and there are quite a few undocumented foot guns along the way. Nevertheless thank you for your effort – just hoping to provide some feedback.

chrisjansky avatar Feb 05 '25 17:02 chrisjansky

Sorry to hear about the migration challenges, Nuxt Content used to do a lot of hidden logic to provide it's behavior.

We designed v3 in a way that reduces hidden logic and provides powerful baseline features to cover almost all of the previous features. However, some aspects weren't clear in the migration docs. The migration docs getting updates with feedbacks to reduce the complexity.

As for null values, I'm thinking about providing a small guide or a simpler solution. Also with your feedback migration guide was updated and I added a section about hidden files. https://content.nuxt.com/docs/getting-started/migration#ignore-dot-files

Thanks for your feedback @chrisjansky

farnabaz avatar Feb 11 '25 13:02 farnabaz

@farnabaz Thanks for the explanation, makes sense – I have some knowledge of SQL (using drizzle ORM a lot lately), so I can imagine where the behaviour is coming from, especially around treatment of null, it’s just that the previously very elegant nuxt/content API took a hit as a part of that.

I hate to necro a closed issue, but can you please check #2148? I am unable to set up global MDC components for nuxt/content – attached is a minimal reproduction. Thanks πŸ™

chrisjansky avatar Feb 11 '25 18:02 chrisjansky

hate to necro a closed issue, but can you please check https://github.com/nuxt/content/issues/2148? I am unable to set up global MDC components for nuxt/content – attached is a minimal reproduction. Thanks πŸ™

I take a look at your reproduction of MDC components.

farnabaz avatar Feb 13 '25 14:02 farnabaz

@chrisjansky Found the issue, You can check with the following PR release to see it in action.

npm i https://pkg.pr.new/@nuxt/content@3127

Ping me if works as expected for you.

farnabaz avatar Feb 13 '25 15:02 farnabaz