'How to get all documents from a collection in FaunaDB?

I already have an answer:

const faunadb = require('faunadb')
const q = faunadb.query

exports.handler = async (event, context) => {
  const client = new faunadb.Client({
    secret: process.env.FAUNADB_SERVER_SECRET
  }) 

  try {  
    // Getting the refs with a first query
    let refs = await client.query(q.Paginate(q.Match(q.Index('skus'))))
    // Forging a second query with the retrieved refs
    const bigQuery = refs.data.map((ref) => q.Get(ref))
    // Sending over that second query
    let allDocuments = await client.query(bigQuery)
    // All my documents are here!
    console.log('@allDocuments: ', allDocuments);
    //...
  } catch (err) {
    // ...
  }
}

But I find it unsatisfying because I'm making 2 queries for what seems like one the most trivial DB call. It seems inefficient and wordy to me.

As I'm just learning about FaunaDB, there's probably something I don't grasp here. My question could be split into 3:

  • Can I query for all documents in a single call?
  • If not, why not? What's the logic behind such a design?
  • Could I make such a query without an index?


Solution 1:[1]

Can I query for all documents in a single call?

Yes, if your collection is small. The Paginate function defaults to fetching 64 documents per page. You can adjust the page size up to 100,000 documents. If your collection has more than 100,000 documents, then you have to execute multiple queries, using cursors to fetch subsequent documents.

See the Pagination tutorial for details: https://docs.fauna.com/fauna/current/tutorials/indexes/pagination

If not, why not? What's the logic behind such a design?

For an SQL database, SELECT * FROM table is both convenient and, potentially, a resource nightmare. If the table contains billions of rows, attempting to serve results for that query could consume the available resources on the server and/or the client.

Fauna is a shared database resource. We want queries to perform well for any user with any database, and that requires that we put sensible limits on the number of documents involved in any single transaction.

Could I make such a query without an index?

No, and yes.

Retrieving multiple results from Fauna requires an index, unless you are independently tracking the references for documents. However, with the Documents function, Fauna maintains an internal index so you don't need to create your own index to access all documents in a collection.

See the Documents reference page for details: https://docs.fauna.com/fauna/current/api/fql/functions/documents

Returning to your example code, you are executing two queries, but they could easily be combined into one. FQL is highly composable. For example:

let allDocuments = await client.query(
  q.Map(
    q.Paginate(q.Documents(q.Collection("skus"))),
    q.Lambda("X", q.Get(q.Var("X")))
  )
)

Your observation that FQL is wordy, is correct. Many functional languages exhibit that wordiness. The advantage is that any functions that accept expressions can be composed at will. One of the best examples of composability, and how to manage inter-document references, is presented in our E-commerce tutorial, specifically, the section describing the submit_order function: https://docs.fauna.com/fauna/current/tutorials/ecommerce#function

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1