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:
- You are just calling
getProjects
beforeawait clientPromise
has resolved - The resolved value of
clientPromise
isundefined
.
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")