#documents scans vs table scans

7 messages · Page 1 of 1 (latest)

novel bluff
sharp domeBOT
#

Hi @novel bluff. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

If you use .take(5) in Convex, it will only scan and retrieve the first 5 documents—it does not scan the whole table. This is much more efficient than using .collect() or .filter() without an index, which can result in a full table scan (i.e., reading every document in the table).

From the documentation:

This document query will not scan more than 5 documents.

const tasks = await ctx.db.query("tasks").take(5);

On the other hand, this document query:

const tasks = await ctx.db
  .query("tasks")
  .filter((q) => q.eq(q.field("isCompleted"), true))
  .first();

might need to walk over every single document in the "tasks" table just to find the first one with isCompleted: true Querying performance and limits.

So, using .take(5) will only count as scanning 5 documents for bandwidth and limit purposes, not the whole table. This is a key optimization in Convex: limiting the number of documents scanned directly reduces bandwidth usage and helps you avoid hitting function limits.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@novel bluff Kapa.ai is still learning and improving, please let me know how I did by reacting below.

novel bluff
#

@sharp dome
const tasks = await ctx.db
.query("tasks")
.filter((q) => q.eq(q.field("isCompleted"), true))
.take(5);

What about this one ?

sharp domeBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

If you use:

const tasks = await ctx.db
  .query("tasks")
  .filter((q) => q.eq(q.field("isCompleted"), true))
  .take(5);

Convex will scan documents in the "tasks" table one by one, applying the filter, and will stop scanning once it has found 5 documents that match isCompleted: true. However, if there are very few matching documents or they are near the end of the table, Convex may need to scan many (or even all) documents to find those 5 matches. So, while .take(5) limits the number of results returned, it does not necessarily limit the number of documents scanned if the filter is not supported by an index.

From the documentation:

This document query will not scan more than 5 documents.

const tasks = await ctx.db.query("tasks").take(5);

On the other hand, this document query:

const tasks = await ctx.db
  .query("tasks")
  .filter((q) => q.eq(q.field("isCompleted"), true))
  .first();

might need to walk over every single document in the "tasks" table just to find the first one with isCompleted: true Querying performance and limits.

The same logic applies to .take(5) after a filter: it will scan until it finds 5 matches, which could mean scanning the whole table in the worst case. To avoid this, you should use an index on the isCompleted field if you expect many documents and want to optimize performance and bandwidth usage.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: