Next.js Discord

Discord Forum

Next.js with mongodb difficulties

Answered
berkserbet posted this in #help-forum
Open in Discord
Hey all! I'm struggling to make this happen. I am moving to a database and want to configure everything correctly. Currently local is kind of working but staging deploys aren't.

Connections to db are working well.

app/api/get/route.ts
import type { NextApiRequest, NextApiResponse } from "next";
import { connectMongoDB } from '@/lib/mongodb';

import Product from "@/models/ProductModel";
import { NextResponse } from "next/server";
import mongoose from "mongoose";

export async function GET() {
  console.log("hit get post", new Date().getSeconds());
  try {
    await connectMongoDB();
    const get = await Product.find({}).limit(60);

    return new NextResponse(JSON.stringify(get));
  } catch (error) {
    console.log("error from route", error);
    return new NextResponse("Error");
  }
}


models/ProductModel.ts
import mongoose from "mongoose";
const Product = new mongoose.Schema();
module.exports = mongoose.models.Product || mongoose.model("Product", Product);


The error on staging deploys is: Type error: Module '"/vercel/path0/models/ProductModel"' has no default export.
Answered by linesofcode
Look at that example and see how they use mongoose
View full answer

101 Replies

You forgot to export Product
In your product model file
export default Product
@linesofcode export default Product
Yeah I tried that, but I get another bug then that breaks local
I add:
export default Product;
The error is Unhandled Runtime Error Error: Unexpected token '<', "<!DOCTYPE "... is not valid JSON

On the find in this line: const get = await Product.find({}).limit(60);
Says:
Property 'find' does not exist on type 'Schema<any, Model<any, any, any, any, any, any>, {}, {}, {}, {}, DefaultSchemaOptions, { [x: string]: unknown; }, Document<unknown, {}, FlatRecord<{ [x: string]: unknown; }>> & FlatRecord<...> & Required<...>>'.ts(2339)
@linesofcode any idea?
That’s a typescript error
I think you’re doing something wrong with the way you’re using mongoose
I’m not very familiar with it sorry
But what I would suggest to do is find a nextjs example on GitHub using mongoose
Yeah I thinkk you're right - do you know how to interact with mongodb without mongoose? I really don't need it
You’d use another mongo client
I don’t use mongo so I can’t recommend any
Quick other question, how can I pass query params to my get request?
Look at that example and see how they use mongoose
Answer
Query parameters are sent in the url
/foobar?param=123
Sure, how can I read them inside my get function
In the get function
You can extract them from the request
I don’t remember the exact syntax
Just Google for it or ask chat gpt
I am new to this so examples I find keep being too complex
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const id = searchParams.get('id')
const res = await fetch(https://data.mongodb-api.com/product/${id}, {
headers: {
'Content-Type': 'application/json',
'API-Key': process.env.DATA_API_KEY!,
},
})
const product = await res.json()

return Response.json({ product })
}
You’ll need to get used to the complexity I’m afraid
I suggest going through the official nextjs tutorial
It will really help
Since it’ll expose you to all these topics
And it won’t seem as complex anymore
@linesofcode And it won’t seem as complex anymore
Will do, thank you!
Good luck.
Komondor
here is an example from my project
import mongoose from 'mongoose'

// the collection is created by NextAuth. This model exists so we can query it.
export interface IAccount extends mongoose.Document {
  userId: mongoose.Schema.Types.ObjectId
}



/* AccountSchema will correspond to a collection in your MongoDB database. */
const AccountSchema = new mongoose.Schema<IAccount>({
  userId: {
    type: mongoose.Schema.Types.ObjectId,
  }
})

export default mongoose.models.Account || mongoose.model<IAccount>('Account', AccountSchema)
that allows me to do
Account.find.......
Komondor
I can't answer for vercel
as long as your db is reachable on the network then you should be good
since you didn't get an error on the db connect part, then I'd imagine it's reachable
@Komondor since you didn't get an error on the db connect part, then I'd imagine it's reachable
I am getting this error on my browser in a staging build:
Application error: a server-side exception has occurred (see the server logs for more information).
Digest: 1634295334

I also don't see my data coming in when I navigate to the get endpoint. On local I do
One vercel I see:
[Error: An error occurred in the Server Components render. The specific message is omitted in production builds to avoid leaking sensitive details. A digest property is included on this error instance which may provide additional details about the nature of the error.] {
  digest: '1634295334'
}
Komondor
you'll have to find some more detailed logs, those only indicate that an error ocurred, they don't state what the error was
Komondor
I'm not familiar with vercel sorry
you could add more console.log logs around the database stuff
to pinpoint where the error is ocurring
but it won't tell you what the error is
or wrap the entire db code in a try/catch and then console log the exception
this link says there is a logs tab
@Komondor https://vercel.com/docs/observability/runtime-logs
I am seeing this error actually:
SyntaxError: Unexpected token < in JSON at position 0
    at JSON.parse (<anonymous>)
    at parseJSONFromBytes (node:internal/deps/undici/undici:4747:19)
    at successSteps (node:internal/deps/undici/undici:4718:27)
    at fullyReadBody (node:internal/deps/undici/undici:1433:9)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async specConsumeBody (node:internal/deps/undici/undici:4727:7)
    at async R (/var/task/.next/server/app/page.js:1:50563)
Komondor
that's probably due to your front end expecting json but instead it's getting html that says INTERNAL SERVER ERROR
Yeah
Komondor
so still not telling us what the error is
@Komondor so still not telling us what the error is
When I go directly to the <url>/api/get I don't get an error but it returns an empty list. Which is confusing. My db isn't local
Komondor
is your db empty?
/app/api/ge/route.ts
import type { NextApiRequest, NextApiResponse } from "next";
import { connectMongoDB } from '@/lib/mongodb';

// import Product from "@/models/ProductModel";
import Product, { Products } from "@/models/ProductModel";
import { NextResponse } from "next/server";
import mongoose from "mongoose";

export async function GET() {
  console.log("hit get post", new Date().getSeconds());
  try {
    await connectMongoDB();
    // const get = await Product.find({'reddit_subreddit': 'EDCexchange'}).skip(60).limit(60);
    const get_res = await Product.find({}).limit(60);
    return new NextResponse(JSON.stringify(get_res));
  } catch (error) {
    console.log("error from route", error);
    return new NextResponse("Error");
  }
}
Nope
It's got a lot in it
Local I see a bunch
Komondor
what's the http status code in chrome developer tools network tab
So I guess it isn't reaching out to the right place maybe
Komondor
so it's 500 when called from your client code, but not 500 when called directly from your browser?
The request url is different than the url I go to
In my code I have this:
const baseUrl = process.env.VERCEL_URL ? 'https://' + process.env.VERCEL_URL : 'http://localhost:3000'
const products_res = await fetch(`${baseUrl}/api/get`)
I guess this is a server side component so I don't see the actuall calls in my browser
this 500 should just be because page showing up
Komondor
you need to find the reason for that 500 error in the vercel logs
did you checkout the link I sent above
@Komondor did you checkout the link I sent above
Looking into it now
Komondor
and you shouldn't be calling your own API from a server component
@Komondor and you shouldn't be calling your own API from a server component
Maybe that's it - can server components access data that updates?
Komondor
server components can access anything on the internet
when the data updates though, your app doesn't know to go refetch it
unless you've coded it to
calling your own api from within a server component won't cause an error
it's just not good practice
So I have a simple one page app that shows a bunch of product listings. How would I show them in a system that has a db?
Komondor
your server component can either fetch the data from the db, and then render that data (or pass it to a client component to render it)

Or, your client component can make an API call to your server, and then your server will fetch the data from the db
The code that reads from the database in your API handler should also be in your server component.

Calling your own API from a server component creates a needless trip to the internet
I see what you're saying - is it ok to interact with a db directly in a server component?
Komondor
yes all code in a server component runs on the server
so it's ok to have sensitive information there
@Komondor so it's ok to have sensitive information there
I was worried about constantly opening and closing db connections
Komondor
since vercel is "serverless", and not long living web servers, I would get in the habbit of closing the db connection after fulfilling the request
I guess I could create a proper backend - I'm a lt more comfortable with python
Or keep opening and closing connections
Komondor
I wouldn't worry about closing connections
I don't think that justifies building a differnet backend
but of course, use what you're comfortable with
So I can basically do something like this in my page.tsx
/* Retrieves pet(s) data from mongodb database */
export const getServerSideProps: GetServerSideProps<Props> = async () => {
  await dbConnect();

  /* find all the data in our database */
  const result = await Pet.find({});

  /* Ensures all objectIds and nested objectIds are serialized as JSON data */
  const pets = result.map((doc) => {
    const pet = JSON.parse(JSON.stringify(doc));
    return pet;
  });

  return { props: { pets: pets } };
};
Grabbed that from an example on github
New connection each time the page loads
Komondor
yep that's what I'm doing
The only reason I mentioned closing the connection is because I've seen some other people on here posting about connection limits being reached
Cool, let me try that now - thanks so much for the help!
Komondor
and I was theorizing that it was due to the serverless architecture and connections not getting cleaned up