Convex doesn’t currently support an efficient IN / OR operator on indexes (the moral equivalent of WHERE field IN (...) in SQL). Instead, the recommended pattern is exactly what you saw: run one indexed query per value and then merge the results in TypeScript. [No efficient in; Union]
Why this isn’t “one query” in Convex
Conceptually, an efficient IN on an index is just N separate range lookups on that index. Convex makes that explicit in the API instead of hiding it behind a single whereIn call. The docs call this out as “No efficient in / or” and show the pattern:
messages: defineTable(...).index("author", ["author"]);
async function authoredMessages(author: string) {
return await ctx.db.query("messages")
.withIndex("author", q => q.eq("author", author)).order("desc")
.collect();
}
const allMessages = await Promise.all(["Alice", "Bob"].map(authoredMessages));
const messages = allMessages.flat()
.sort((a, b) => b._creationTime - a._creationTime);
[Union]
There’s also a QueryStream version that merges multiple indexed streams and paginates them as one logical result. [Union]
Is this grossly inefficient?
According to the Convex team, no—this is the efficient way to do it: