skip to Main Content

I’m using next.js 14.2 and want to change the "comment" field in my mongo database.
here is my server action:

export async function addAComment(proposalId: number, newComment: string) {
  await connectDB();
  const updateFields: any = {};
  updateFields.comment = newComment;
  console.log("here is a new comment:", newComment);
  const result = await ProposalModel.findOneAndUpdate(
    { proposalId: proposalId },
    { $set: updateFields },
    { new: true }
  );

  console.log("comment added, this is resut:", result);
}

i’m not sure if i need to add connectDB(), but the issue is , that if i do connectDB(), i get

Error connecting to MongoDB: TypeError: Cannot read properties of undefined (reading '0')

that means it is already connected to db
and if i don’t do connectDB()
I get

TypeError: _mongodb_proposalSchema__WEBPACK_IMPORTED_MODULE_2__.default.findOneAndUpdate is not a function

here is my connectDB:

import mongoose from "mongoose";

const connectDB = async () => {
  try {
    if (mongoose.connections[0].readyState) {
      // If already connected, do nothing
      console.log("Already connected to MongoDB");
      return;
    }

    await mongoose.connect(process.env.MONGODB_URI as string, {
      //serverSelectionTimeoutMS: 70000,
    });

    console.log("Connected to MongoDB");
  } catch (error) {
    console.error("Error connecting to MongoDB:", error);
    throw error; // Ensure error is thrown to be caught by the calling function
  }
};

export default connectDB;

and here is how i handle it in frontend:


  const [comment, setComment] = useState("");
  const handleSendTransaction = async () => {

    if (comment.length) {
      //await connectDB();
      await addAComment(proposalId, comment);
    }


  };
....
<button
          onClick={handleSendTransaction} >
          Send Transaction
        </button>

what is confusing, is that this same code (adding comment to db) with connectDB works fine if i copy it in other directory make it into a script and run it with

npx ts-node index.ts

does anyone have any idea how this error can be fixed?

UPD: now addAComment looks like this: (no connectDB())

export async function addAComment(proposalId: number, newComment: string) {
  const updateFields: any = {};
  updateFields.comment = newComment;
  console.log("here is a new comment:", newComment);
  const result = await ProposalModel.findOneAndUpdate(
    { proposalId: proposalId },
    { $set: updateFields },
    { new: true }
  );

  console.log("comment added, this is resut:", result);
}

and I’m getting

TypeError: _mongodb_proposalSchema__WEBPACK_IMPORTED_MODULE_2__.default.findOneAndUpdate is not a function

here is my schema:

import { Document, Model, Schema, model, models } from "mongoose";

interface IProposalDocument extends Document {
  proposalId: number;
  toCompanyAddress: string;
  fromAddress: string;
  proposalURI: string;
  decisionStatus: number;
  fundingGoal: string;
  currentFunding: string;
  deadline: string;
  comment?: string; // Making this field optional
}

const proposalSchema: Schema<IProposalDocument> = new Schema(
  {
    proposalId: {
      type: Number,
      required: true,
      unique: true, // Ensure unique proposalId
    },
    toCompanyAddress: {
      type: String,
      required: true,
    },
    fromAddress: {
      type: String,
      required: true,
    },
    proposalURI: {
      type: String,
      required: true,
    },
    decisionStatus: {
      type: Number,
      required: true,
    },
    fundingGoal: {
      type: String,
      required: true,
    },
    currentFunding: {
      type: String,
      required: true,
    },
    deadline: {
      type: String,
      required: true,
    },
    comment: {
      type: String,
      default: "", // Default to an empty string
    },
  },
  { timestamps: true }
);

const ProposalModel: Model<IProposalDocument> =
  models?.proposals || model<IProposalDocument>("proposals", proposalSchema);

2

Answers


  1. A module scoped mongoose object will make use of the same connection in all subsequent invocation of connect method. Therefore there is no need to handle the same in app.

    At present the issue comes from the below statement, which does the same job which mongoose does it for the app. Therefore it may be avoided.

     ...if (mongoose.connections[0].readyState) {...
    

    The following code shows the same point, mongoose object in module scope makes use of the same connection in all subsequent calls of connect method. Even though the method connect has been invoked thrice in the code below, there is only one connected event fired as shown in the console.

    const mongoose = require('mongoose');
    
    mongoose.connect('mongodb://127.0.0.1:27017/test');
    mongoose.connection.on('connected', () => console.log('connected'));
    mongoose.connection.on('disconnected', () => console.log('disconnected'));
    
    function checkConnection() {
      run();
      run();
      mongoose.connection.close();
    }
    
    function run() {
      mongoose.connect('mongodb://127.0.0.1:27017/test');
    }
    
    checkConnection();
    

    Output

    connected
    disconnected
    

    Links:

    1. Mongoose Events doesn’t fire on connection

    2. What is the right way to create a cached MongoDB connection using Mongoose?

    Login or Signup to reply.
  2. The issues you’re encountering seem to be due to a mix of connection management and possible module loading problems. Let’s address them step-by-step:

    Step 1: Ensure Connection Management
    Make sure that your connection management logic (connectDB) works correctly and is used properly in your application.

    Step 2: Verify Mongoose Model and Schema
    Ensure your Mongoose model and schema are defined and exported correctly.

    Step 3: Correctly Handle the Database Connection in Next.js
    Ensure the database connection logic is properly handled within the Next.js environment.

    Here is a revised approach to address these issues:

    Connection Management:
    Your connectDB function looks mostly correct, but let’s ensure it’s always exporting properly and is used correctly within your addAComment function.

    Model Definition:
    Make sure the ProposalModel is correctly defined and accessible.

    Using connectDB and ProposalModel:
    Ensure you’re importing and using them correctly in your server action.

    Revised Code

    connectDB.ts (Connection Management)

    import mongoose from 'mongoose';
    const connectDB = async () => {
      try {
        if (mongoose.connections[0].readyState) {
          console.log('Already connected to MongoDB');
          return;
        }
        await mongoose.connect(process.env.MONGODB_URI as string, {
          useNewUrlParser: true,
          useUnifiedTopology: true,
        });
    
        console.log('Connected to MongoDB');
      } catch (error) {
        console.error('Error connecting to MongoDB:', error);
        throw error;
      }
    };
    
    export default connectDB;
    

    proposalModel.ts (Model Definition)

    import { Document, Model, Schema, model, models } from 'mongoose';
    
    interface IProposalDocument extends Document {
      proposalId: number;
      toCompanyAddress: string;
      fromAddress: string;
      proposalURI: string;
      decisionStatus: number;
      fundingGoal: string;
      currentFunding: string;
      deadline: string;
      comment?: string;
    }
    
    const proposalSchema: Schema<IProposalDocument> = new Schema(
      {
        proposalId: { type: Number, required: true, unique: true },
        toCompanyAddress: { type: String, required: true },
        fromAddress: { type: String, required: true },
        proposalURI: { type: String, required: true },
        decisionStatus: { type: Number, required: true },
        fundingGoal: { type: String, required: true },
        currentFunding: { type: String, required: true },
        deadline: { type: String, required: true },
        comment: { type: String, default: '' },
      },
      { timestamps: true }
    );
    
    const ProposalModel: Model<IProposalDocument> = models.proposals || model<IProposalDocument>('proposals', proposalSchema);
    
    export default ProposalModel;
    

    serverAction.ts (Server Action)

    import connectDB from './connectDB';
    import ProposalModel from './proposalModel';
    
    export async function addAComment(proposalId: number, newComment: string) {
      await connectDB();
      const updateFields: any = { comment: newComment };
    
      console.log('Here is a new comment:', newComment);
      try {
        const result = await ProposalModel.findOneAndUpdate(
          { proposalId: proposalId },
          { $set: updateFields },
          { new: true }
        );
        console.log('Comment added, this is the result:', result);
        return result;
      } catch (error) {
        console.error('Error updating comment:', error);
        throw error;
      }
    }
    

    Usage in Next.js Component

    Ensure you call addAComment correctly from your component:

    import { useState } from 'react';
    import { addAComment } from './serverAction';
    
    const CommentComponent = ({ proposalId }) => {
      const [comment, setComment] = useState('');
    
      const handleSendTransaction = async () => {
        if (comment.length) {
          try {
            const result = await addAComment(proposalId, comment);
            console.log('Comment updated:', result);
          } catch (error) {
            console.error('Error adding comment:', error);
          }
        }
      };
    
      return (
        <div>
          <input
            type="text"
            value={comment}
            onChange={(e) => setComment(e.target.value)}
            placeholder="Add a comment"
          />
          <button onClick={handleSendTransaction}>Send Transaction</button>
        </div>
      );
    };
    
    export default CommentComponent;
    

    Hope that with these changes, your code should correctly handle database connections and perform updates without prematurely closing the connection.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search