Next.js MongoDB integration with API routes
January 12, 2021
Install the required mongo library
npm i -S mongodb
Setup connection details for local development environment
We assume that you already have a mongodb instance ready and running somewhere, meaning that you have a connection string, database and collection details at hand.
This needs to be setup on your local dev environment e.g.: .env.local
.
We’ll setup them as follows
DATABASE_URL =
"mongodb://rpi.fritz.box:27017/iphonePro?replicaSet=rs0&ssl=false"
MONGO_DB = "iphonePro"
MONGO_AD_COLLECTION = "ads"
Create a DB connection helper function
We will use this in the API routes later to connect to the database.
// https://raw.githubusercontent.com/vercel/next.js/canary/examples/with-mongodb/util/mongodb.js
import { MongoClient } from "mongodb"
const { DATABASE_URL, MONGO_DB } = process.env
if (!DATABASE_URL) {
throw new Error(
"Please define the DATABASE_URL environment variable inside .env.local"
)
}
if (!MONGO_DB) {
throw new Error(
"Please define the MONGO_DB environment variable inside .env.local"
)
}
/**
* Global is used here to maintain a cached connection across hot reloads
* in development. This prevents connections growing exponentially
* during API Route usage.
*/
let cached = global.mongo
if (!cached) {
cached = global.mongo = { conn: null, promise: null }
}
export async function connectToDatabase() {
if (cached.conn) {
return cached.conn
}
if (!cached.promise) {
const opts = {
useNewUrlParser: true,
useUnifiedTopology: true,
}
cached.promise = MongoClient.connect(DATABASE_URL, opts).then(client => {
return {
client,
db: client.db(MONGO_DB),
}
})
}
cached.conn = await cached.promise
return cached.conn
}
Create an API Route for a Mongo DB operation
In /pages/api/db
create the DB operation function, e.g.: for insertion, as follows:
import { connectToDatabase } from "../../../helpers/db"
const insertOneToMongo = async (req, res) => {
const { db } = await connectToDatabase()
const { body } = req
const { payload, collection } = body
console.log(payload, collection)
try {
await db.collection(process.env[collection]).insertOne(payload)
res.status(200).json({ result: "success" })
} catch (e) {
console.error(e)
res.status(500).send(e)
}
}
export default insertOneToMongo
Similarly for data retrieval from Mongo:
import { connectToDatabase } from "../../../helpers/db"
const getOneFromMongo = async (req, res) => {
const { db } = await connectToDatabase()
const { query } = req
const { qry, collection } = query
try {
const result = await db
.collection(process.env[collection])
.findOne(JSON.parse(qry))
res.status(200).json({ result })
} catch (e) {
console.error(e)
res.status(500).send(e)
}
}
export default getOneFromMongo
One more, for mongo upsert
(insert in case record with a provided filter condition does not exist, otherwise update):
import { connectToDatabase } from "../../../helpers/db"
const replaceOneInMongo = async (req, res) => {
const { db } = await connectToDatabase()
const { body } = req
const { filter, payload, upsert, collection } = body
try {
await db
.collection(process.env[collection])
.replaceOne(filter, payload, { upsert })
res.status(200).json({ result: "success" })
} catch (e) {
console.error(e)
res.status(500).send(e)
}
}
export default replaceOneInMongo
Call these from your code where needed
How to call these functions in your code? See sample below (using the mongo upsert function we just created before)
const saveInternalProfile = () => {
setshowInsertModal(true)
setTimeout(async () => {
try {
const _profile = { ...profile }
delete _profile._id
await Axios.post("/api/db/replaceOneInMongo", {
filter: { email: profile.email },
payload: _profile,
upsert: true,
collection: "MONGO_INTERNAL_USERS_COLLECTION",
})
setshowInsertModal(false)
toast.success("Profile mentése sikeres")
} catch (error) {
setshowInsertModal(false)
toast.error("Profile mentése sikertelen")
}
}, 500)
}
Hope this helps.