I’m developing a NextJS
app with Mongoose
.
And I get a "Cannot read properties of null (reading 'get')"
error when I try to use my models from Mongoose.
Here is a screenshot of the error:
I’ve checked that I’ve imported my models correctly and initialized Mongoose correctly, but I can’t find the cause of this error.
models/Order.js :
import {model, models, Schema} from "mongoose";
import mongoose from 'mongoose';
const OrderSchema = new mongoose.Schema({
products: {
type: Object,
required: true,
},
user_id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
address: {
type: String,
required: true,
},
city: {
type: String,
required: true,
},
paid: {
type: Number,
default: 0
},
}, {timestamps: true});
const Order = models?.Order || model('Order', OrderSchema)
export default Order;
models/User.js:
import {model, models, Schema} from "mongoose";
const UserSchema = new Schema( {
email:{
type:String,
required:true,
unique:true,
},
password:{
type:String,
required:true,
}
});
const User = typeof models === 'object' ? models.User : model('User', UserSchema);
export default User ;
And front side I call my data in pages folder of nextjs
pages/orders.js:
import { useEffect, useState } from "react";
import axios from "axios";
import jwt from "jsonwebtoken";
import cookie from "cookie";
import Order from "../models/Order";
function Orders() {
const [orders, setOrders] = useState([]);
useEffect(() => {
async function fetchOrders() {
const res = await axios.get("/api/secret");
const secret = res.data.secret;
// Get the JWT token from the cookies
const token = cookie.parse(document.cookie).OursiteJWT;
const decoded = jwt.verify(token, secret);
const userId = decoded._id
// Fetch the orders for the user from the backend API
const response = await axios.get(`/api/orders?user_id=${userId}`);
const orders = response.data;
// Populate the user_id field in each order with the associated user object
const populatedOrders = await Promise.all(orders.map(async (order) => {
return await Order.findById(order._id).populate("user_id");
}));
setOrders(populatedOrders);
}
fetchOrders();
}, []);
return (
<div>
{orders.map((order) => (
<div key={order._id}>
<h2>Commande {order._id}</h2>
<p>Utilisateur: {order.user_id.name}</p>
<p>Adresse: {order.address}</p>
<p>Ville: {order.city}</p>
<p>Produits:</p>
<ul>
{order.products.map((product) => (
<li key={product._id}>{product.name}</li>
))}
</ul>
</div>
))}
</div>
);
}
export default Orders;
api/orders :
/* eslint-disable import/no-anonymous-default-export */
import Order from "../../models/Order";
import {initMongoose} from "../../lib/mongoose";
initMongoose()
export default async function(req, res) {
// Get the user ID from the query string
const userId = req.query.user_id;
// Find the orders for the user
const orders = await Order.find({ user_id: userId }).populate("user_id");
// Send the orders as the response
res.json(orders);
};
api/secret :
export default async function handler(req, res) {
const { method } = req;
if (method === 'GET') {
res.json({ secret: process.env.SECRET });
} else {
res.setHeader('Allow', ['GET']);
res.status(405).end(`Method ${method} Not Allowed`);
}
}
3
Answers
mongoose
is server-side package. you cannot use the Order model inside client components. You can use models with server-side code, inside api functions or getServerSide functions.The Order Schema should be –
You are trying to create an express route handler inside a Next.js route handler. Refactor the code in
api/secret
to this:If you also want this route to follow the REST protocol and only allow a GET request to be accepted, you can use the following: