#combined search index
8 messages · Page 1 of 1 (latest)
Hi @terse berry. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
Unfortunately, you cannot combine .withSearchIndex() and .withIndex() in a single query in Convex. A query can only use a single index, and a search index is both an index and an order (by relevance), making it incompatible with a regular index in the same query. [dynamic query builders]
Workarounds
Option 1: Use .withSearchIndex() with a filter field
If userId is a field you want to filter on alongside the search, you can define it as a filterFields in your search index:
// schema.ts
podcasts: defineTable({
name: v.string(),
userId: v.id("users"),
}).searchIndex("by_name", {
searchField: "name",
filterFields: ["userId"],
})
Then query like this:
await ctx.db
.query("podcasts")
.withSearchIndex("by_name", (q) =>
q.search("name", search ?? "").eq("userId", userId)
)
.collect();
This lets you filter by userId within the search index itself. Note that _creationTime range filtering is not supported in search index filter expressions.
Option 2: Conditional query (search vs. index)
If the search term is optional, use two separate queries depending on whether a search term is provided:
const result = search
? await ctx.db
.query("podcasts")
.withSearchIndex("by_name", (q) =>
q.search("name", search).eq("userId", userId)
)
.collect()
: await ctx.db
.query("podcasts")
.withIndex("by_userId", (q) =>
q.eq("userId", userId).gte("_creationTime", key)
)
.collect();
This is a known pattern in the Convex community — using a search index when a search term exists, and falling back to a regular index otherwise. [search index empty query]
Key limitation
The _creationTime range filter (.gte("_creationTime", key)) cannot be used inside a search index. If you need both full-text search and time-range filtering, you'd need to post-filter the search results in TypeScript after collecting them.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@terse berry Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@wintry slate but how do i get the pagination with the aggregat component with the search
Let me check the knowledge base for you again. One moment! :books:
The knowledge sources do not contain enough information to describe how to combine the Aggregate component with a search index for pagination.
What the knowledge sources do cover is:
-
Aggregate component is useful for offset-based pagination (e.g., skip to page N) and counting, but it works with regular database indexes — not search indexes. [offset-based pagination]
-
Search index pagination uses
.paginate(paginationOpts)directly on a.withSearchIndex()query, like:
export const list = query({
args: { paginationOpts: paginationOptsValidator },
handler: async (ctx, args) => {
return await ctx.db
.query("podcasts")
.withSearchIndex("by_name", (q) =>
q.search("name", search ?? "").eq("userId", userId)
)
.paginate(args.paginationOpts);
},
});
Then use usePaginatedQuery on the frontend. [paginated queries]
However, the knowledge sources do not describe a supported pattern for combining the Aggregate component with a search index query. The Aggregate component's offset-based pagination works with regular indexes, and it's unclear from the available sources whether it can be used alongside search indexes.