#Array Fields as Indexes in Convex
4 messages · Page 1 of 1 (latest)
Hi @ember helm. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
Convex does allow you to define indexes on array fields, but there are important limitations and considerations:
Can array fields be used as indexes in Convex?
You can technically create an index on an array field, for example:
export default defineSchema({
posts: defineTable({
body: v.string(),
tags: v.array(v.string()),
}).index("by_tags", ["tags"]),
});
However, the way Convex indexes work means that the index is sorted by the entire array value. This allows you to efficiently query for documents where the array exactly matches a value (e.g., ["happy"]) or starts with a specific prefix, but not for documents that merely contain a specific value somewhere in the array. For example, querying for all posts that contain "happy" in their tags array is not efficient or directly supported with .withIndex on an array field. The index does not group together all documents containing a particular tag, so you can't use .withIndex to efficiently filter for array containment in this way Optimize with Indexes.
Is it possible to store tags as an array and filter documents containing specific tags using withIndex?
No, not efficiently. While you can store tags as an array, using .withIndex on that array field will not let you efficiently filter for documents containing a specific tag. You would have to fetch all documents and filter them in memory using JavaScript, which is not scalable for large datasets Filter too complex? Do it in TypeScript.
What are the considerations and recommended patterns?
-
For small datasets or prototyping: Filtering in TypeScript after fetching all documents is fine.
-
For scalable queries: The recommended pattern is to create a separate "join" table that maps each tag to the documents containing it. For example:
export default defineSchema({ posts: defineTable({ body: v.string(), tags: v.array(v.string()), }), tagged_posts: defineTable({ tag: v.string(), post: v.id("posts"), }).index("by_tag", ["tag"]), });When you add or update a post, you also update the
tagged_poststable. Then, to find all posts with a given tag, you querytagged_postsby tag and join back to the posts table. This is efficient and scalable Optimize with Indexes. -
Bandwidth considerations: Filtering in TypeScript after fetching all documents means all documents are read from the database, which counts against your bandwidth quota—even if they are filtered out later Discord: Query, filtering array of IDs.
Summary
- You can index array fields, but
.withIndexdoes not support efficient "contains" queries on arrays. - For efficient filtering by array contents, use a join table pattern.
- Filtering in TypeScript is fine for small datasets, but not scalable.