Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The mongodb documentation is outdated and doesn't match the provided source code #29891

Closed
wise-introvert opened this issue Oct 13, 2021 · 9 comments
Labels
bug Issue was opened via the bug report template. examples Issue/PR related to examples

Comments

@wise-introvert
Copy link

What example does this report relate to?

with-mongodb

What version of Next.js are you using?

11.1.2

What version of Node.js are you using?

14.17.6

What browser are you using?

Brave

What operating system are you using?

Ubuntu

How are you deploying your application?

Vercel

Describe the Bug

The with-mongodb documentation specifies a file, called mongodb.js inside the utils directory of the with-mongodb example project that seems to have been removed from the actual project on github and this is causing discrepancies in the documentation. The current example project does not have the utils directory at all and has been replaced with the lib directory. The default export from the mongodb file has also changed from connectToDatabase to clientPromise.

Expected Behavior

The documentation should be up to date with the latest project structure and logic.

To Reproduce

Visit the documentation website and compare it with the given project source code

@wise-introvert wise-introvert added bug Issue was opened via the bug report template. examples Issue/PR related to examples labels Oct 13, 2021
@Rallanvila
Copy link

I'm experiencing the same exact problem. I was able to find the older repo here: https://github.com/kukicado/nextjs-with-mongodb/blob/master/util/mongodb.js

However, i'd like to use the most updated version that gets downloaded from "npx create-next-app --example with-mongodb" but the documentation is outdated on how to manage the data.

@Rallanvila
Copy link

Rallanvila commented Oct 17, 2021

@wise-introvert I was able to find the fix. I moved around the comments to make it flow better. If you look at the commit changes and go by the lines added you'll find these added to the bottom of the index in the getServerSideProps function.

// client.db() will be the default database passed in the MONGODB_URI
// You can change the database by calling the client.db() function and specifying a database like:
// const db = client.db("myDatabase");
// Then you can execute queries against your database like so:
// db.find({}) or any of the MongoDB Node Driver commands

this means instead of running const {db} = await connectToDatabase(); you'll instead run const db = await client.db()

Below is a sample of the code I ran that pulled from MongoDB successfully and rendered on the page. I left the comments in so you can see what's happening:

import Head from "next/head";
import clientPromise from "../lib/mongodb";

export default function Home({ drinks }) {
	return (
		<div>
			<h1>Hello World</h1>
			<p>{drinks.map((drink) => drink.title)}</p>
		</div>
	);
}

export async function getServerSideProps(context) {
    const client = await clientPromise;

    // client.db() will be the default database passed in the MONGODB_URI
    const db = await client.db();
    // You can change the database by calling the client.db() function and specifying a database like:
	// const db = client.db("myDatabase");
	// Then you can execute queries against your database like so:
	// db.find({}) or any of the MongoDB Node Driver commands

	const drinks = await db
		.collection("menu")
		.find({
			category: { $in: ["hot-coffee", "iced-coffee"] },
		})
		.toArray();

	return {
		props: { drinks: JSON.parse(JSON.stringify(drinks)) },
	};
}

Hope this helps!

@wise-introvert
Copy link
Author

@Rallanvila thanks! Will try it out and let you know.

@Rafi-99
Copy link

Rafi-99 commented Oct 20, 2021

@kukicado Sorry for the ping, but is there anything you can suggest? Like the author mentioned, the example that's on GitHub right now is not working with the latest MongoDB driver version and is not consistent with the documentation.

@joegiusto
Copy link

@Rafi-99 using @Rallanvila response I was able to get everything working. You might need to update all your files but it works. If you need this working in an API route it would be the following.

import clientPromise from 'lib/mongodb';

export default async function handler(req, res) {

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

    const result = await db
    .collection("products")
    .find()
    .toArray();

    res.json(result);
    
};

@Rafi-99
Copy link

Rafi-99 commented Oct 20, 2021

@joegiusto Thanks for your response! I tried changing some code and was able to get something to display on my page using Rallanvila's example of getServerSideProps(). However, the second I add another collection from the same database, I run into issues. Some of my data is showing up as undefined when it shouldn't. Also, does the example implement connection caching? Man, I keep getting a different issue each time I rewrite my code.

@Rafi-99
Copy link

Rafi-99 commented Oct 20, 2021

Below is my Database Helper class

import { MongoClient } from 'mongodb';

export default class DatabaseService {
    static cached_connection_instance;
    static url = process.env.MONGO_URL
    static client = new MongoClient(this.url, { useNewUrlParser: true, useUnifiedTopology: true }); 

    static getConnection() {
        if(!DatabaseService.cached_connection_instance) {
            DatabaseService.cached_connection_instance = DatabaseService.createConnection();
        }
        return DatabaseService.cached_connection_instance;
    }

    static createConnection() {
        this.client.connect();
    }
}

Below is my about.js file

import Image from 'next/image';
import DatabaseService from '../utils/DatabaseService';
import styles from '../styles/pages/about.module.css'; 

export default function about({ isConnected, skills, jobs }) {
    return (
        <>
            <div className={styles.intro}>
                <h1>Rafi - Software Engineer @ TCS</h1>
                <Image src = "/assets/images/LinkedIn.jpg" width = {250} height = {250} layout = "intrinsic" alt = "A picture of Rafi." className = {styles.picture} quality = "100" />

                <p>Hey guys my name is Rafi!/p>
            </div>

            {isConnected ? 
                <>
                    <div className={styles.list}>
                        {skills.map((skill) => ( 
                            <div key={skill._id}>   
                                <p>{skill.category}</p> 
                                <p>{skill.description}</p>
                            </div>
                        ))}
                    </div>
                    
                    <div className={styles.list}>        
                        {jobs.map((job) => (
                            <div key={job._id}>  
                                <p>{job.job_title}</p>  
                                <p>{job.job_location}</p>
                                <p>{job.job_duration}</p> 
                                <div>{job.job_description.map((bullet, i) => (<p key={i}>{bullet}</p>))}</div> 
                            </div>
                        ))}
                    </div>
                </>
            : <p style={{textAlign: "center"}}>Failed to connect to MongoDB. Please refresh.</p>} 
        </>
    );
};

export async function getServerSideProps() {
    let isConnected;

    try {
        await DatabaseService.getConnection();
        
        const skills = await DatabaseService.client.db("résumé").collection("skills").find().sort({ _id: 1 }).toArray(); 
        const jobs = await DatabaseService.client.db("résumé").collection("work_experience").find().sort({ _id: -1 }).limit(5).toArray();     
        isConnected = true; 
        DatabaseService.client.close();
     
        return {
            props: { 
                isConnected: true,
                skills: JSON.parse(JSON.stringify(skills)), 
                jobs: JSON.parse(JSON.stringify(jobs)) 
            }
        };
    }
    catch(error) {
        console.error("Error fetching from MongoDB", error);
        return { 
            props: {
                isConnected: false
            }
        };
    }
}; 

This code works for the most part, but the issue is I can't seem to cache my connections correctly. Also, the data doesn't appear when you first start the page. It will only show on the second reload. Accessing the page for the first time will give you an "Error fetching from MongoDB MongoNotConnectedError: MongoClient must be connected to perform this operation" error. I appreciate any guidance you can offer. Frustrated with trying to figure this out for hours.

@wise-introvert
Copy link
Author

@Rafi-99 your code worked like a charm for me. Was struggling with coming up with something generic like that for a while. Thanks a ton!

To people who stumble on this thread and are using typescript 😉:

import { MongoClient } from "mongodb";

export class DatabaseService {
  static cached_connection_instance: MongoClient;
  static url: string = process.env.MONGO_URL || "mongodb://localhost:27017";
  static client: MongoClient = new MongoClient(this.url);

  static async getConnection(): Promise<MongoClient> {
    if (!DatabaseService.cached_connection_instance) {
      DatabaseService.cached_connection_instance =
        await DatabaseService.createConnection();
    }
    return DatabaseService.cached_connection_instance;
  }

  static async createConnection(): Promise<MongoClient> {
    return this.client.connect();
  }
}

@balazsorban44
Copy link
Member

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@vercel vercel locked as resolved and limited conversation to collaborators Jan 27, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Issue was opened via the bug report template. examples Issue/PR related to examples
Projects
None yet
Development

No branches or pull requests

5 participants