DEV Community

loizenai
loizenai

Posted on

Mongoose One-to-Many Relationship Example

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.

Objective - Mongoose One-to-Many Relationship Example

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

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);
});

Create a NodeJS/Express project - Mongoose One-to-Many Relationship Example

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 Mongoose 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);

Nodejs Express RestAPI Route - Mongoose One-to-Many Relationship Example

  • 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);
}

Nodejs Express RestAPI 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 - Mongoose One-to-Many Relationship Example

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

[caption id="attachment_4820" align="alignnone" width="705"]Node.js Mongodb One-to-many Related Document Initial Data - Mongoose One-to-Many Relationship Example Node.js Mongodb One-to-many Related Document Initial Data[/caption]

  • Get all Companies:

-> localhost:8081/api/companies

[caption id="attachment_4821" align="alignnone" width="452"]Nodejs Mongodb One-to-many Related Document Find All Company - Mongoose One-to-Many Relationship Example Nodejs Mongodb One-to-many Related Document Find All Company[/caption]

  • Get all Products

-> localhost:8081/api/products

[caption id="attachment_4822" align="alignnone" width="440"]Nodejs Mongodb One-to-many Related Document Find All Product - Mongoose One-to-Many Relationship Example Nodejs Mongodb One-to-many Related Document Find All Product[/caption]

  • Find Product by Name:

-> localhost:8081/api/product/Iphone7

[caption id="attachment_4823" align="alignnone" width="410"]Nodejs Mongodb One-to-Many Related Document Find Product By Name Polulate Company - Mongoose One-to-Many Relationship Example Nodejs Mongodb One-to-Many Related Document Find Product By Name Polulate Company[/caption]

  • Find Products by Company Id:

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

[caption id="attachment_4824" align="alignnone" width="532"]Nodejs Mongodb One-to-many Related Document Find All Products By Company ID Nodejs Mongodb One-to-many Related Document Find All Products By Company ID[/caption]

Read More

Related posts:

Top comments (0)