Dynamic route query DB - return a single element based on ID

Hello,

I have followed the well explained tutorial on how to integrate MongoDB in Next.JS

I have been able to query the DB to get the list of one collection, but I am now struggling to get one document of a collection based on its ID.

import React from "react";
import Head from "next/head";
import clientPromise from "../../lib/mongodb";
import { ObjectId } from "mongodb";

export default function CompanyShow(companyData) {
  return (
    <div>
      {" "}
      <h1>{companyData.name}</h1>...
    </div>
  );
}

export async function getStaticPaths() {
  // Return a list of possible value for id

  const client = await clientPromise;
  const db = client.db("main");

  const companies = db.collection("companies");

  // here you can filter for certain data entries in your db
  // in this case we only want the ids
  const data = await companies.find({}, { _id: 1 }).toArray();

  client.close();

  return {
    // no 404 page will be rendered in case an id is entered which doesn't exist
    fallback: "blocking",

    // dynamcly calculating the routes
    paths: data.map((datapoint) => ({
      params: {
        companyId: datapoint._id.toString(),
      },
    })),
  };
}

export async function getStaticProps({ context }) {
  const client = await clientPromise;
  const db = client.db("main");

  const companies = db.collection("companies");

  // Fetch necessary data for the company using params.id
  const companyId = context.params.companyId;

  // filter the companies for the companyId you get from context.params.companyId;
  const selectedCompanyEntry = await companies.findOne({
    _id: ObjectId(companyId),
  });

  client.close();

  return {
    props: {
      companyData: {
        id: selectedCompanyEntry._id.toString(),
        name: selectedCompanyEntry.name,
      },
    },
    revalidate: 1,
  };
}

Right now on that iteration I am getting an error of undefined params.

Would you be as kind as helping me fix that issue please?

Or orienting me towards a new page documentation of MongoDB explaining step by step how to do it?

Thank you!

Hi @Marving_Moreton ,

The query looks correct to me:

const selectedCompanyEntry = await companies.findOne({
    _id: ObjectId(companyId),
  });

I suspect the issue is with context.params which might be passed wrongly…

Can you share a full error you get and the line that message it?

Thanks
Pavel

Hello @Pavel_Duchovny, thank you for your reply!

Well… I had some evolution to it!

I had a destructuring issue with passing ( {context}) instead of (contex†).

However, now I am getting a new error: BSONTypeError: Argument passed in must be a string of 12 bytes or a string of 24 hex characters or an integer

It seems that const companyId does not get the _id but the whole object as a whole:

import React from "react";
import Head from "next/head";
import clientPromise from "../../lib/mongodb";
import { ObjectId } from "mongodb";

export default function CompanyShow(props) {
  return (
    <div>
      <h1>{props.companyData.name}</h1>...
    </div>
  );
}

export async function getStaticPaths() {
  // Return a list of possible value for id

  const client = await clientPromise;
  const db = client.db("main");

  const companies = db.collection("companies");

  // here you can filter for certain data entries in your db
  // in this case we only want the ids
  const data = await companies.find({}, { _id: 1 }).toArray();

  client.close();

  return {
    // no 404 page will be rendered in case an id is entered which doesn't exist
    fallback: "blocking",

    // dynamcly calculating the routes
    paths: data.map((datapoint) => ({
      params: {
        companyId: datapoint._id.toString(),
      },
    })),
  };
}

export async function getStaticProps(context) {
  const client = await clientPromise;
  const db = client.db("main");

  const companies = db.collection("companies");

  // Fetch necessary data for the company using params.id
  // const companyId = context.params.companyId;
  console.log(context.params.companyId);

  // console.log(ObjectId(params.companyId));
  const companyId = context.params.companyId;

  // filter the companies for the companyId you get from context.params.companyId;
  const selectedCompanyEntry = await companies.findOne({
    _id: ObjectId(companyId),
  });

  client.close();

  return {
    props: {
      companyData: {
        id: selectedCompanyEntry._id.toString(),
        name: selectedCompanyEntry.name,
      },
    },
    revalidate: 1000,
  };
}

Hi @Marving_Moreton ,

So it looks like the value of companyId is. not a valid string containing an actual ObjectId format.

Please debug your code and verify that the string you provide is constructed to be converted to an objectId…

Thank
Pavel

2 Likes

Yeah I have figured my error.

I were looking to have the [slug] as URL and not the Id itself

1 Like