#Indexes on fields within nested objects
7 messages · Page 1 of 1 (latest)
Hi @royal marsh. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
Yes, this has come up a few times, and the short answer is: yes, you can index fields inside nested objects using dot-separated paths.
From the docs:
- Database indexes: when defining an index, “to specify a field on a nested document, use a dot-separated path like
properties.name.” [Indexes] - Vector indexes: “You can specify vector and filter fields on nested documents by using a dot-separated path like
properties.name.” [Vector search] - Full‑text search indexes: same pattern for
searchFieldandfilterFields. [Text search]
So for your example:
export default defineSchema({
myTable: defineTable({
foo: v.object({ bar: v.string() }),
}).index("by_foo_bar", ["foo.bar"]),
});
This is a supported and documented pattern.
There’s also a Discord thread on “custom fields” where staff explicitly confirm: “You can index on a nested document” and link to the same indexes doc. [Custom fields thread]
If you need to query it:
const rows = await ctx.db
.query("myTable")
.withIndex("by_foo_bar", q => q.eq("foo.bar", someString))
.collect();
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@royal marsh Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@wary stag What's the behaviour of such indexes when the nested object is absent ? field is assumed to be undefined?
Let me check the knowledge base for you again. One moment! :books:
Yes, the field is treated as undefined when the nested object (or the nested field) is absent.
The docs state that for filters and index queries, missing fields are considered undefined, and you can even query them that way:
You can use
undefinedin filters and index queries, and it will match documents that do not have the field. i.e.
.withIndex("by_a", q => q.eq("a", undefined))matches{}and{b: 1}, but not{a: 1}or{a: null, b: 1}. [Working with undefined]
This applies equally to nested paths like "foo.bar": if foo is missing or doesn’t have bar, then "foo.bar" is treated as undefined for the purposes of index ordering and comparisons. The same section also notes Convex’s ordering:
In Convex's ordering scheme,
undefined < null < all other values. [Working with undefined]
So:
- Docs where
foo.baris missing will behave as iffoo.bar === undefined. - You can explicitly query for “no value” with
.eq("foo.bar", undefined). - You can query for “has some value” with something like
.gt("foo.bar", undefined)or.gte("foo.bar", null as any)if needed.