NodeJs/Express MongoDB One-to-Many related documents

nodejs-express-mongodb-one-to-many-related-models-feature-image

In the tutorial, we will show you how to develop One-to-Many related document with NodeJs/Express, MongoDB using Mongoose.

Related post:
Crud RestAPIs with NodeJS/Express, MongoDB using Mongoose
Mongoose Many-to-Many related models with NodeJS/Express, MongoDB

Goal

Prerequisites

Crud RestAPIs with NodeJS/Express, MongoDB using Mongoose
In the above tutorial, we show how to build CRUD RestAPIs with NodeJS/Express and MongoDB using Mongoose:


/nodejs-restapi-mongodb
	/app
		/config
			mongodb.config.js
		/controllers
			customer.controller.js
		/models
			customer.model.js
		/routes
			customer.routes.js
	/node_modules
	package.json
	server.js

Objective

In the tutorial, we show how to develop One-to-Many related documents with NodeJS/Express, MongoDB. Project structure:


/nodejs-restapi-mongodb
	/app
		/config
			mongodb.config.js
		/controllers
			companies.controller.js
			products.controller.js
		/models
			company.model.js
			product.model.js
		/routes
			companies.routes.js
			products.routes.js
	/node_modules
	package.json
	server.js

One-to-Many related models

For working with related documents, we use the ObjectId schema field.

-> CompanySchema:


const Product = require('../models/product.model.js');
const mongoose = require('mongoose'), Schema = mongoose.Schema;

const CompanySchema = mongoose.Schema({
	name: String,
    street: String,
    phone: String
});

module.exports = mongoose.model('Company', CompanySchema);

-> ProductSchema:


const Company = require('../models/company.model.js');
const mongoose = require('mongoose'), Schema = mongoose.Schema;

const ProductSchema = mongoose.Schema({
    code: String,
    name: String,
	details: String,
	company : { type: Schema.Types.ObjectId, ref: 'Company' }
});

module.exports = mongoose.model('Product', ProductSchema);

We can save the references to the related document by assigning the _id value:


var apple = new Company({ 
	name: 'Apple', 
	street: 'Cupertino, CA 95014', 
	phone: '1-408-996-1010' 
});

apple.save(function (err) {
if(err) return console.error(err.stack)

console.log("Apple company is added")

//Apple now exists, so lets create a Product
var iphone7 = new Product({
  code: "A-123",
  name: "Iphone7",
  details: "Price: 649.00 USD & FREE shipping",
  company: apple._id
});

iphone7.save(function (err) {
  if(err) return console.error(err.stack)
  
  console.log("Iphone 7 is added")
});
});

We use populate() to get the Company information in Product:


Product.findOne({ name: req.params.productName })
.populate('company')
.exec(function (err, product) {
	if (err){
		// handle error here
		...
	}
				
	res.send(product);
});

We didn’t add our products to companies, how to get all products by a particular company?

One way, we create a references array field of products in CompanySchema as below:


const Product = require('../models/product.model.js');
const mongoose = require('mongoose'), Schema = mongoose.Schema;

const CompanySchema = mongoose.Schema({
	name: String,
    street: String,
    phone: String,
	products : [{ type: Schema.Types.ObjectId, ref: 'Product' }]
});

module.exports = mongoose.model('Company', CompanySchema);

BUT What is problem? -> We have two places where the information relating companies and products needs to be maintained.

What is the better solution?

-> We get the _id of our company, then use find() to search for this in the company field across all products.


Product.find({ company : req.params.companyId })
.exec(function (err, products) {
	if (err){
		// handle error here
		...
	}
				
	res.send(products);
});

Practice

Create a NodeJS/Express project

Following below guide:
Crud RestAPIs with NodeJS/Express, MongoDB using Mongoose

See dependencies in ‘package.json’ file:


  "dependencies": {
    "body-parser": "^1.18.2",
    "express": "^4.16.3",
    "mongoose": "^5.0.13",
    "npm": "^5.8.0"
  }

Create Model Schema

CompanySchema:


const Product = require('../models/product.model.js');
const mongoose = require('mongoose'), Schema = mongoose.Schema;

const CompanySchema = mongoose.Schema({
	name: String,
    street: String,
    phone: String,
	products : [{ type: Schema.Types.ObjectId, ref: 'Product' }]
});

module.exports = mongoose.model('Company', CompanySchema);

ProductSchema:


const Company = require('../models/company.model.js');
const mongoose = require('mongoose'), Schema = mongoose.Schema;

const ProductSchema = mongoose.Schema({
    code: String,
    name: String,
	details: String,
	company : { type: Schema.Types.ObjectId, ref: 'Company' }
});

module.exports = mongoose.model('Product', ProductSchema);

Route

Company Routes:


module.exports = function(app) {

	var companies = require('../controllers/companies.controller.js')
	
	app.get('/api/companies/init', companies.init);
	app.get('/api/companies', companies.findAll);
}

Product Routes:


module.exports = function(app) {
    var products = require('../controllers/products.controller.js');
	
	app.get('/api/products', products.findAll);
			
	// Find a single Product by Name
    app.get('/api/products/:productName', products.findByName);
	
	// Find all Products of a Company
    app.get('/api/products/company/:companyId', products.findByCompanyId);
}

Controller

Company Controllers:


const Company = require('../models/company.model.js');
const Product = require('../models/product.model.js');

exports.init = (req, res) => {
  var apple = new Company({ 
	name: 'Apple', 
	street: 'Cupertino, CA 95014', 
	phone: '1-408-996-1010' 
  });

  apple.save(function (err) {
    if(err) return console.error(err.stack)
	
	console.log("Apple company is added")
	
    //Apple now exists, so lets create a Product
    var iphone7 = new Product({
	  code: "A-123",
	  name: "Iphone7",
	  details: "Price: 649.00 USD & FREE shipping",
	  company: apple._id
    });

    iphone7.save(function (err) {
	  if(err) return console.error(err.stack)
	  
	  console.log("Iphone 7 is added")
    });
	
	var iPadPro = new Product({
	  code: "A-456",
	  name: "IPadPro",
	  details: "Price: 417.67 USD & FREE shipping",
	  company: apple._id
	});
	
	iPadPro.save(function(err){
		if(err) return console.error(err.stack)
		
		console.log("IPadPro is added");
	});
	
  });
  
  
  var samsung = new Company({ 
		name: 'Samsung', 
		street: 'Seocho District, Seoul, South Korea', 
		phone: '+82-2-2053-3000'
	});
  
  samsung.save(function(err){
	if(err) return console.error(err.stack)
	
	console.log("Samsung company is added")
	
	// Samsung now exists, so lets create a Product
	var galaxyJ7 = new Product({
	  code: "S-012",
	  name: "GalaxyJ7",
	  details: "Price: 219.00 USD & FREE shipping",
	  company: samsung._id	
	});
	
	galaxyJ7.save(function(err){
		if(err) return console.error(err.stack)
		console.log("GalaxyJ7 is added")
	});
	
	var galaxyTabA = new Product({
	  code: "S-456",
	  name: "GalaxyTabA",
	  details: "Price: 299.99 USD & FREE shipping",
	  company: samsung._id
	});
	
	galaxyTabA.save(function(err){
		if(err) return console.error(err.stack)
		console.log("GalaxyTabA is added")
	})
  });
  
  res.send("Done Initial Data!");
}

exports.findAll = (req, res) => {
	Company.find()
    .then(products => {
        res.send(products);
    }).catch(err => {
        res.status(500).send({
            message: err.message
        });
    });
};

Product Controllers:


const Company = require('../models/company.model.js');
const Product = require('../models/product.model.js');

exports.findAll = (req, res) => {
	
	Product.find()
    .then(products => {
        res.send(products);
    }).catch(err => {
        res.status(500).send({
            message: err.message
        });
    });
};

// Find a Products by Name
exports.findByName = (req, res) => {
	Product.findOne({ name: req.params.productName })
	.populate('company')
	.exec(function (err, product) {
		if (err){
			if(err.kind === 'ObjectId') {
				return res.status(404).send({
					message: "Products not found with given name " + req.params.productName
				});                
			}
			return res.status(500).send({
				message: "Error retrieving Products with given Company Id " + req.params.productName
			});
		}
					
		res.send(product);
	});
};

// Find all products by a CompanyId
exports.findByCompanyId = (req, res) => {
	Product.find({ company : req.params.companyId })
	.exec(function (err, products) {
		if (err){
			if(err.kind === 'ObjectId') {
				return res.status(404).send({
					message: "Products not found with given Company Id " + req.params.companyId
				});                
			}
			return res.status(500).send({
				message: "Error retrieving Products with given Company Id " + req.params.companyId
			});
		}
					
		res.send(products);
	});
};

Run & Check results

Run MongDB server by commandline:


\MongoDB\Server\3.6\bin>mongod.exe
2018-04-11T03:11:42.209+0700 I CONTROL  [initandlisten] MongoDB starting : pid=2432 port=27017 dbpath=C:\data\db\ 64-bit host=LOI-COMPUTER
2018-04-11T03:11:42.211+0700 I CONTROL  [initandlisten] targetMinOS: Windows 7/Windows Server 2008 R2
2018-04-11T03:11:42.212+0700 I CONTROL  [initandlisten] db version v3.6.3
2018-04-11T03:11:42.212+0700 I CONTROL  [initandlisten] git version: 9586e557d54ef70f9ca4b43c26892cd55257e1a5
2018-04-11T03:11:42.212+0700 I CONTROL  [initandlisten] OpenSSL version: OpenSSL 1.0.1u-fips  22 Sep 2016
2018-04-11T03:11:42.212+0700 I CONTROL  [initandlisten] allocator: tcmalloc

Run NodeJS/Express application:


\nodejs-restapi-mongodb>node server.js
App listening at http://:::8081
Successfully connected to MongoDB.

– Initial data
-> localhost:8081/api/companies/init

nodejs-mongodb-one-to-many-related-document-initial data

– Get all Companies
-> localhost:8081/api/companies

nodejs-mongodb-one-to-many-related-document-find all company

– Get all Products
-> localhost:8081/api/products

nodejs-mongodb-one-to-many-related-document-find all product

– Find Product by Name
-> localhost:8081/api/product/Iphone7

nodejs-mongodb-one-to-many-related-document-find product by name - polulate company

– Find Products by Company Id
-> localhost:8081/api/products/company/5acd590b203d8e1ac01cb184

nodejs-mongodb-one-to-many-related-document-find all products by company id

Sourcecode

NodeJS-MongoDB-One-to-Many

5 thoughts on “NodeJs/Express MongoDB One-to-Many related documents”

  1. This is really great and a lot helpful guide while I was starting a project. The code structure really guided me in a certain way.
    You could also give us the best way to design a server side folder structure (a better approach).

  2. Thanks for your personal marvelous posting! I
    genuinely enjoyed reading it, you could be
    a great author. I will always bookmark your blog and may
    come back later in life. I want to encourage yourself to continue your great job,
    have a nice evening!

  3. hello there and thank you for your information – I’ve
    definitely picked up anything new from right here.

    I did however expertise some technical issues using this web site,
    since I experienced to reload the web site many times previous to I
    could get it to load properly. I had been wondering if your web hosting is OK?
    Not that I am complaining, but sluggish loading instances times will very frequently affect your placement in google and could damage your high quality score
    if ads and marketing with Adwords. Well I’m adding
    this RSS to my email and can look out for much more of your respective intriguing content.
    Make sure you update this again very soon.

Leave a Reply

Your email address will not be published. Required fields are marked *