Home > front end >  Top level function not running when export is called inside getStaticPaths()
Top level function not running when export is called inside getStaticPaths()

Time:08-03

I am accessing a database from a Next.js SSG (static site generation) app. In order to prevent the app from having to reconnect to the db every time I make a query, I am exporting a global promise from one file and then calling it in a separate file (controllers.js) that contains multiple functions that directly query the db. Those functions are then called from within the getStaticProps() and getStaticPaths() methods in my actual components. Here is the code for controllers.js:

import clientPromise from "./clientPromise";

let client;
let db;

(async function () {
  // Await cannot be used outside of an async function (on the top level/module).
  // So we must call it below inside this async function that we immediately call instead of above where it is initialized.
  client = await clientPromise;
  db = client.db("dev"); // use development database
})();

// Query "technologies" collection:
export async function getTechnologies() {
  const technologies = await db
    .collection("technologies")
    .find({})
    .toArray();
  return JSON.parse(JSON.stringify(technologies));
}

// Query "projects" collection:
export async function getProjects() {
  const projects = await db
  .collection("projects")
  .find({})
  .toArray();
  return JSON.parse(JSON.stringify(projects));
}

And here is a snippet of where I am calling the my controllers:

// This works perfectly:
export async function getStaticProps() {
    const projects = await getProjects();

    return {
        props: { projects: projects },
    }
};

// This causes the error:
export async function getStaticPaths() {
    const projects = await getProjects();

    return {
        paths: [{ params: {_id: "placeholder"} }],
        fallback: false,
    };
}

The error I'm getting is telling me that db is undefined and therefore I can't use the method "collection" on it. What I have concluded is that my anonymous async function which should be calling itself immediately is not running when getProjects() is called within getStaticPaths() and therefore db is not being defined causing the error. Everything works when I call getProjects() inside getStaticProps(), what is going on?

CodePudding user response:

If db is undefined at the time you call getProjects then one of two things has happened:

  1. You are just calling getProjects before await clientPromise has resolved
  2. The resolved value of clientPromise is undefined.

You've not provided enough information to debug the second possibility, so let's assume the first is the problem here.


(async function () {
  // Await cannot be used outside of an async function (on the top level/module).
  // So we must call it below inside this async function that we immediately call instead of above where it is initialized.
  client = await clientPromise;
  db = client.db("dev"); // use development database
})();

You've got an async function here which returns a promise and you could use that promise to determine when the result was available.

Instead you've taken a fire-and-forget approach and are depending on a side effect that you can't control the timing of.

Take advantage of the fact it returns a promise.

const db = (async function () { 
    const client = await clientPromise;
    const devdb = client.db("dev");
    return devdb;
}();

Now db will be a promise that resolves to the value you want immediately instead of being undefined and then changing later.

You'll need to change the rest of your module to account for that of course. For example:

const projects = await db
    .collection("projects")

will become

const devdb = await db;
const projects = devdb.collection("projects")
  • Related