DevStronauT
DevStronauT•6mo ago

Query documents by array of documentIds possible?

Is there any way to get the documents by array of documentIds? here I'm querying my documentIds in array! const collaborators = await ctx.db .query("collaborators") .withIndex("by_email", (q) => q.eq("email", args.email)) .collect(); const documentIds = collaborators.map(collaborator => collaborator.document); Now I want to query all the documents whose _id presents in documentIds array!
12 Replies
Hmza
Hmza•6mo ago
const documents = await Promise.all( documentIds.map(async (id) => { return await ctx.db.get("documents", id); }) ); this should work
DevStronauT
DevStronauTOP•6mo ago
I tried this one but I'm wondering if there are any inbuild convex queries to do so!
Hmza
Hmza•6mo ago
you can use filter from convex helpers then to directly filter "documents"
Hmza
Hmza•6mo ago
Using TypeScript to Write Complex Query Filters
There’s a new Convex helper to perform generic TypeScript filters, with the same performance as built-in Convex filters, and unlimited potential.
lee
lee•6mo ago
i would say Promise.all is the built-in convex way to do it. under the hood it queues up all of the db.get requests on the js microtask queue, and then when you await them all together it does a batched fetch with the by_id index. (by contrast, filter scans the whole table, which is probably less efficient)
DevStronauT
DevStronauTOP•6mo ago
That's great point @lee So 1 or 2? 1. filter from helpers! const documents = await filter(ctx.db.query("documents"), (document) => documentIds.includes(document._id) ).collect(); 2. Promise.all() by Javascript !! const documents = await Promise.all( documentIds.map(async (id) => { return await ctx.db.get(id); }) ); 👀 ?? 1st one will have n db quires depending on length of documentIds array! 2nd one has only one query to DB but 2 heavy tasks 1stly fething all the documents in one go may be there are thousands and 2ndly filtering on that n number of documents!! Bit confused here!
lee
lee•6mo ago
1st one will have n db quires depending on length of documentIds array!
no, the first one is equivalent to
const allDocuments = await ctx.db.query("documents").collect();
const documents = allDocuments.filter((document) =>
documentIds.includes(document._id));
const allDocuments = await ctx.db.query("documents").collect();
const documents = allDocuments.filter((document) =>
documentIds.includes(document._id));
DevStronauT
DevStronauTOP•6mo ago
Oh sorry I mean 2nd one swap the content please for both the points!!
lee
lee•6mo ago
ah true i would always do the 2nd one. it's almost always going to be more efficient. the only time the 1st would be more efficient is if the set of document ids is on the same order of magnitude as the full "documents" table.
DevStronauT
DevStronauTOP•6mo ago
That's cool thanks @lee
lee
lee•6mo ago
btw this is one of the things i like about convex: we let you pick the query plan. i've fought with mysql and postgres where i give a query like SELECT document FROM documents WHERE id IN (1, 2) and it says "i think it will be faster to scan the entire documents table than look up 2 documents via the index on the id column." And then my query's performance plummets. in Convex that won't happen; you can tell it to do a table scan or you can ask it to do 100 point lookups; it won't decide and in particular it won't make the wrong decision.

Did you find this page helpful?