Mongodb Relational Documents with Node.js and Express
As a beginner many people are confused on how to relate documents in Mongodb. In this article we will design our models, perform few crud operations and make relations between documents.
We will be using Mongoose in this tutorial with MongoDB Compass. If you want to learn more about mongoose you can read from official document at Mongoose ODM v6.6.5 (mongoosejs.com). The other main thing is that you must have MongoDB install, ideally with MongoDB Compass as I’ll be using it in this tutorial. Lastly, if you are working with Node environment you should have all required dependencies installed.
To get started we will first create our server side that will be on Node.js with Express.js. We will create a folder, navigate it in terminal and run the below command
npm init -y
Next we will download all the dependencies via this command
npm install express mongoose nodemon cors dotenv moment
next we will create a file called server.js in our main folder. You main folder will now look like this
Next we will add a script in our package.json so that on change of any file our server will restart and reflect immediate change.
{"name": "relational-documents","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","dev": "nodemon server.js"},"keywords": [],"author": "","license": "ISC","dependencies": {"cors": "^2.8.5","express": "^4.18.1","mongoose": "^6.6.5","nodemon": "^2.0.20"}}
Now we will add basic code to our server.js to run our server.
require('dotenv').config()const express = require("express");const app = express();const bodyParser = require("body-parser");var cors = require("cors");
const moment = require("moment");app.use(bodyParser.urlencoded());app.use(bodyParser.json());app.use(cors());var mongoose = require("mongoose");const mongoAtlasUri = `mongodb://localhost:27017/mongooseRelationExample`try {// Connect to the MongoDB clustermongoose.connect(mongoAtlasUri,{ useNewUrlParser: true, useUnifiedTopology: true },() => console.log("Mongoose is connected"),);} catch (e) {console.log("could not connect");}const dbConnection = mongoose.connection;dbConnection.on("error", (err) => console.log(`Connection error ${err}`));dbConnection.once("open", () => console.log("Connected to DB!"));app.use((_, res) =>{res.send({message: 'Not found!'})});app.listen(5000, (req, res)=>{console.log("Server is listening on port 5000");})
Now we will run our server by the following command
npm run dev
Once server is running, we will then proceed to structure our app and add “models” folders. I will be making all router and logic in server.js file but if you want to follow best practice, I recommend reading my previous post Node.js project structure.
Now your main folder will look like this.
Now we will plan our db. Let’s consider we have a schema called person and each person is assigned a task. We will first create a schema of people then each another schema of tasks. Now each task will be assigned to a person. We will perform basic operations on it like insert delete and find.
Now first create a file called person.js.
const mongoose = require('mongoose');const { Schema } = mongoose;const personSchema = new mongoose.Schema({first_name:{type: String},last_name:{type: String},creation_date: {type: String},updation_date: {type: String}})module.exports = mongoose.model('Person', personSchema);
Now let’s create a post request to add a person in server.js.
app.post("/person/create", (req, res)=>{try {const person = new Person({first_name: req.body.first_name,last_name: req.body.last_name,creation_date: moment().format("MMMM Do YYYY, h:mm:ss a")});person.save();res.send({status: 'success',message: `${req.body.first_name} successfully added!`});} catch (error) {console.log(error)res.send({status: 'error',message: error});}});
Make sure that you import mongoose and person schema in server.js file
var mongoose = require("mongoose");const Person = require('./models/person');
Now open postman to hit a post request. If you don’t have Postman you can either download it from their website or can also use online.
Now that the person can be added let’s make another model for tasks in task.js.
const mongoose = require('mongoose');const { Schema } = mongoose;const taskSchema = new mongoose.Schema({task_name: {type: String},task_status: {type: String,default: "pending"},assigned_to: {type: mongoose.Schema.Types.ObjectId,ref: 'Person'},creation_date: {type: String},updation_date: {type: String}})module.exports = mongoose.model('Task', taskSchema);
Next add a post request to add a task aswell.
app.post("/task/create", (req, res)=>{try {const task = new Task({task_name: req.body.name,assigned_to: req.body.personId,creation_date: moment().format("MMMM Do YYYY, h:mm:ss a")});task.save();res.send({status: 'success',message: `${req.body.task_name} successfully added!`});} catch (error) {console.log(error)res.send({status: 'error',message: error});}});
Make sure to import Task at the top of server.js
Now let’s open postman again a create a task using API.
Now how did I add personId? Where did I get it from? Earlier we added a person, I just went to MongoDB Compass and refreshed it and copy the person id and paste it in postman. It is not recommended to copy paste ids like this but as it is just for learning I am doing it like that.
Now that a task is added you can test if the relational ship was made correctly or not. I’ll add a get request to get all task with user details with “.populate()”. It is bit similar to joins in SQL database.
app.get("/tasks/view", (req, res)=>{Task.find().populate('assigned_to').exec(function(error, docs){if(!error){res.status(200).json({status: "success",data: docs})}else{console.log(error)res.send({status: "error",error: error})}})})
Now we will request it through Postman.
Now you can make more complex relations in any logic. It just needs practice, and you will be able to use it easily.
You can view this project at my github repo MuqtadirBillah/mongodb_relations (github.com)
Follow me for more interesting tips and tricks at Musab Abbasi — Medium
You can also find me on LinkedIn and Github