Mongoose One-to-Many Relationship Example
Tags: mongoose, onetomany, node
Published: 2021-03-05 15:24:54

https://loizenai.com/mongoose-one-to-many-relationship-example/

- Tutorial: "Mongoose One-to-Many Relationship Example - Mongodb One-to-Many Relationship Example"

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

<!--more-->
<h2 id="objective-mongoose-one-to-many-relationship-example">Objective - Mongoose One-to-Many Relationship Example</h2>
In the tutorial, we show how to develop One-to-Many related documents with NodeJS/Express, MongoDB. Project structure:

<pre><code class="language-javascript">
/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
</code></pre>
<h2 id="one-to-many-related-models">One-to-Many related models - Mongoose One-to-Many Relationship Example</h2>
For working with related documents, we use the <strong>ObjectId</strong> schema field.

- CompanySchema:

<pre><code class="language-javascript">
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);
</code></pre>

- ProductSchema:

<pre><code class="language-javascript">
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);
</code></pre>

We can save the references to the related document by assigning the <strong>_id</strong> value:

<pre><code class="language-javascript">
  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")
    });
});
</code></pre>

We use <code>populate()</code> to get the Company information in Product:

<pre><code class="language-javascript">
	Product.findOne({ name: req.params.productName })
	.populate('company')
	.exec(function (err, product) {
		if (err){
			// handle error here
			...
		}
					
		res.send(product);
	});
</code></pre>

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:

<pre><code class="language-javascript">
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);
</code></pre>

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

<strong>What is the better solution?</strong>

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

<pre><code class="language-javascript">
Product.find({ company : req.params.companyId })
.exec(function (err, products) {
	if (err){
		// handle error here
		...
	}
				
	res.send(products);
});
</code></pre>
<h2 id="create-node-js-express-project">Create a NodeJS/Express project - Mongoose One-to-Many Relationship Example</h2>
Following below guide:
<a href="https://ozenero.com/node-js/crud-restapis-with-nodejs-express-mongodb">Crud RestAPIs with NodeJS/Express, MongoDB using Mongoose</a>

See dependencies in 'package.json' file:

<pre><code class="language-javascript">
  "dependencies": {
    "body-parser": "^1.18.2",
    "express": "^4.16.3",
    "mongoose": "^5.0.13",
    "npm": "^5.8.0"
  }
</code></pre>
<h2 id="create-mongoose-model-schema">Create Mongoose Model Schema</h2>
- CompanySchema:

<pre><code class="language-javascript">
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);
</code></pre>

- ProductSchema :

<pre><code class="language-javascript">
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);
</code></pre>
<h2 id="node-js-express-restapi-router">Nodejs Express RestAPI Route - Mongoose One-to-Many Relationship Example</h2>
- Company Routes :

<pre><code class="language-javascript">
module.exports = function(app) {

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

- Product Routes :

<pre><code class="language-javascript">
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);
}
</code></pre>
<h2 id="node-js-express-restapi-controller">Nodejs Express RestAPI Controller</h2>
- Company Controllers :

<pre><code class="language-javascript">
const Company = require('../models/company.model.js');
const Product = require('../models/product.model.js');

exports.init = (req, res) =&gt; {
  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) =&gt; {
	Company.find()
    .then(products =&gt; {
        res.send(products);
    }).catch(err =&gt; {
        res.status(500).send({
            message: err.message
        });
    });
};
</code></pre>

- Product Controllers :

<pre><code class="language-javascript">
const Company = require('../models/company.model.js');
const Product = require('../models/product.model.js');

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

// Find a Products by Name
exports.findByName = (req, res) =&gt; {
	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) =&gt; {
	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);
	});
};</code></pre>
<h2 id="node-js-run-check-results">Run & Check results - Mongoose One-to-Many Relationship Example</h2>
Run MongDB server by commandline:
<pre><code class="language-javascript">
\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
</code></pre>

Run NodeJS/Express application:

<pre><code class="language-javascript">
\nodejs-restapi-mongodb>node server.js
App listening at http://:::8081
Successfully connected to MongoDB.
</code></pre>

- Initial data

-> <code>localhost:8081/api/companies/init</code>

[caption id="attachment_4820" align="alignnone" width="705"]<img src="https://loizenai.com/wp-content/uploads/2021/01/Node.js-Mongodb-One-to-many-Related-Document-Initial-Data.png" alt="Node.js Mongodb One-to-many Related Document Initial Data - Mongoose One-to-Many Relationship Example" width="705" height="387" class="size-full wp-image-4820" /> Node.js Mongodb One-to-many Related Document Initial Data[/caption]

- Get all Companies:

-> <code>localhost:8081/api/companies</code>

[caption id="attachment_4821" align="alignnone" width="452"]<img src="https://loizenai.com/wp-content/uploads/2021/01/Nodejs-Mongodb-One-to-many-Related-Document-Find-All-Company.png" alt="Nodejs Mongodb One-to-many Related Document Find All Company - Mongoose One-to-Many Relationship Example" width="452" height="341" class="size-full wp-image-4821" /> Nodejs Mongodb One-to-many Related Document Find All Company[/caption]

- Get all Products

-> <code>localhost:8081/api/products</code>

[caption id="attachment_4822" align="alignnone" width="440"]<img src="https://loizenai.com/wp-content/uploads/2021/01/Nodejs-Mongodb-One-to-many-Related-Document-Find-All-Product.png" alt="Nodejs Mongodb One-to-many Related Document Find All Product - Mongoose One-to-Many Relationship Example" width="440" height="547" class="size-full wp-image-4822" /> Nodejs Mongodb One-to-many Related Document Find All Product[/caption]

- Find Product by Name:

-> <code>localhost:8081/api/product/Iphone7</code>

[caption id="attachment_4823" align="alignnone" width="410"]<img src="https://loizenai.com/wp-content/uploads/2021/01/Nodejs-Mongodb-One-to-Many-Related-Document-Find-Product-By-Name-Polulate-Company.png" alt="Nodejs Mongodb One-to-Many Related Document Find Product By Name Polulate Company - Mongoose One-to-Many Relationship Example" width="410" height="313" class="size-full wp-image-4823" /> Nodejs Mongodb One-to-Many Related Document Find Product By Name Polulate Company[/caption]

- Find Products by Company Id:

-> <code>localhost:8081/api/products/company/5acd590b203d8e1ac01cb184</code>

[caption id="attachment_4824" align="alignnone" width="532"]<img src="https://loizenai.com/wp-content/uploads/2021/01/Nodejs-Mongodb-One-to-many-Related-Document-Find-All-Products-By-Company-ID.png" alt="Nodejs Mongodb One-to-many Related Document Find All Products By Company ID" width="532" height="371" class="size-full wp-image-4824" /> Nodejs Mongodb One-to-many Related Document Find All Products By Company ID[/caption]
<h2 id="read-more">Read More</h2>
<div class="div-loizenai-pre-related-post">
Related posts:
<hr>
<ul class="ul-loizenai-pre-related-post">
<li><a href="https://loizenai.com/sequelize-one-to-many-create-example/">Sequelize One to Many Create Example</a></li>
<li><a href="https://loizenai.com/mongoose-relationships-many-to-many/">Mongoose Relationship Many to Many</a></li>
<li><a href="https://loizenai.com/spring-boot-one-to-many/">Spring Boot One-to-Many Relationship Example</a></li>
<li><a href="https://loizenai.com/angular-10-nodejs-mongodb-crud-restapi-example/">Angular 10 Node.js MongoDB CRUD Example</a></li>
<li><a href="https://loizenai.com/angular-8-nodejs-mongodb-crud-example/">Angular 8 Nodejs MongoDB CRUD Example</a></li>
<li><a href="https://loizenai.com/angular-9-nodejs-mongodb-crud-example/">Angular 9 Node.js MongoDB CRUD Example</a></li>
</ul>
</div>

- Reference Link: <a href="https://mongoosejs.com/docs/populate.html">Mongoose Association</a>
<h2>Sourcecode</h2>
<p class="sourcecode-lzai">
<a href="https://loizenai.com/wp-content/uploads/2021/01/Node.js-MongoDB-One-to-Many-Example.zip">Node.js-MongoDB-One-to-Many-Example</a>
</p>