DEV Community

Gurkirat Singh
Gurkirat Singh

Posted on

Pocket Guide on Mongoose ODM for NodeJS

Course Overview

Prerequisite Knowledge

Basics of NodeJS

What you will learn in this course

In this, you will learn about the NoSQL database, whose subtle introduction was given in the sequelize's course. Also, you will learn the basics of MongoDB, the leading NoSQL DB support provider and the Mongoose ODM developed my Automattic

Project

The project is in project directory

NOTE: This course is made with jupyter notebook. If you want the notebook drop a message at tbhaxor@gmail.com. I will be adding more topics under misc, so make sure you subscribe to the repository.

What is NoSQL Database

NoSQL database is a type of database that doesn’t follow the approach that SQL follows. It uses different query language and the document doesn’t have to stick to the same schema. The records in it have no relations, duplication of data is preferred

The database contains collections, collections contains documents. These documents are the records. It stores the data in binary JSON (called bson)

What is MongoDB

MongoDB is a NoSQL database service provided by the company named MongoDB. It is specially built for large scale applications, that may store lots and lots of data.

The documents within documents are known as embedded documents. MongoDB uses this way to duplicate the document. Another concept of linking other documents is called references, where the unique id (in MongoDB it's called object id and denoted by _id) of the document is added in the document

Embedded Document way

{
    "_id": "id1",
    "name": "Gurkirat Singh",
    "age": 22,
    "address": {
        "state": "Rajasthan",
        "country": "India"
    }
}
Enter fullscreen mode Exit fullscreen mode

Now the referencing approach needs two separate documents of address and user

Address Document

{
    "_id": "id2",
    "state": "Rajasthan",
    "country": "India"
}
Enter fullscreen mode Exit fullscreen mode

User Document

{
    "_id": "id1",
    "name": "Gurkirat Singh",
    "age": 22,
    "address": "id2"
}
Enter fullscreen mode Exit fullscreen mode

Setting up MongoDB

Installing on Windows: Documentation | Video

Installing on Linux: Documentation | Video

Or you can use MongoDB Atlas. Learn how to set up the cluster from this video → https://www.youtube.com/watch?v=YZ66YqGPip8

Installing MongoDB Compass

  1. Visit the link → https://docs.mongodb.com/compass/current/install/
  2. Select the OS
  3. Follow the instructions on the page.

After installing compass, follow the instructions from the docs to connect it with your MongoDB instance

Installing MongoDB Driver for NodeJS

# using yarn
yarn add mongodb

# using npm
npm i mongodb
Enter fullscreen mode Exit fullscreen mode
const { MongoClient } = require("mongodb") 
Enter fullscreen mode Exit fullscreen mode

After this, you can connect to the MongoDB server by MongoClient.connect() method. It requires a connection string with the following syntax

mongodb://[user:password]@hostname[:port]/database
Enter fullscreen mode Exit fullscreen mode

The data in [ ] are optional. Since I am using MongoDB on my localhost with test db, therefore the connection string in my case will be

mongodb://localhost/test
Enter fullscreen mode Exit fullscreen mode
let db = null;

MongoClient.connect("mongodb://localhost/test", {
    useUnifiedTopology: true // recommended by mongoclient
}).then(client => {
    db = client.db() // getting the object of database
    console.log("Connected to the DB")
}).catch(e => console.warn(e))
Enter fullscreen mode Exit fullscreen mode
Connected to the DB
Enter fullscreen mode Exit fullscreen mode

CRUD Operations on the database

CREATE Document

db.collection("users").insertOne({name: "Gurkirat", age: 22})
    .then(response => console.log(response.result))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
{ n: 1, ok: 1 }
Enter fullscreen mode Exit fullscreen mode

Creating Document in Bulk

let users = [
    { name:"Amit", age: 20 }, 
    { name:"John", age: 25 }
]
Enter fullscreen mode Exit fullscreen mode
db.collection("users").insertMany(users)
    .then(response => console.log(response.result))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
{ ok: 1, n: 2 }
Enter fullscreen mode Exit fullscreen mode

READ Document

db.collection("users").find().toArray().then(r => {
    console.log(r)
}).catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
[
  { _id: 5e89a3c678852a72f87479f8, name: 'Gurkirat', age: 22 },
  { _id: 5e89a46778852a72f87479f9, name: 'Amit', age: 20 },
  { _id: 5e89a46778852a72f87479fa, name: 'John', age: 25 }
]
Enter fullscreen mode Exit fullscreen mode

Did you see the new field _id. It is an auto generated he 12-byte value called ObjectId. It consists of:

  • a 4-byte timestamp value, representing the ObjectId’s creation, measured in seconds since the Unix epoch
  • a 5-byte random value
  • a 3-byte incrementing counter, initialized to a random value

Fetching Single Record

db.collection("users").find({ name: "John" }).next()
    .then(r => console.log(r))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
{ _id: 5e89a46778852a72f87479fa, name: 'John', age: 25 }
Enter fullscreen mode Exit fullscreen mode

Fetching Record by ObjectID

You can compare the ObjectID with string

const { ObjectId }  = require("mongodb")
Enter fullscreen mode Exit fullscreen mode
db.collection("users").find({ "_id": ObjectId("5e89a3c678852a72f87479f8") }).next()
    .then(r => console.log(r))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
{ _id: 5e89a3c678852a72f87479f8, name: 'Gurkirat', age: 22 }
Enter fullscreen mode Exit fullscreen mode

UPDATE Document

db.collection("users").updateOne({ "_id": ObjectId("5e89a3c678852a72f87479f8") }, {$set: { name: "Gurkirat Singh" }})
    .then(r => console.log(r.result))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
{ n: 1, nModified: 0, ok: 1 }
Enter fullscreen mode Exit fullscreen mode
db.collection("users").find({ "_id": ObjectId("5e89a3c678852a72f87479f8") }).next()
    .then(r => console.log(r))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
{ _id: 5e89a3c678852a72f87479f8, name: 'Gurkirat Singh', age: 22 }
Enter fullscreen mode Exit fullscreen mode

DELETE Document

db.collection("users").deleteOne({ "_id": ObjectId("5e89a3c678852a72f87479f8") })
    .then(r => console.log(r.result))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
{ n: 1, ok: 1 }
Enter fullscreen mode Exit fullscreen mode
db.collection("users").find().toArray().then(r => {
    console.log(r)
}).catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
[
  { _id: 5e89a46778852a72f87479f9, name: 'Amit', age: 20 },
  { _id: 5e89a46778852a72f87479fa, name: 'John', age: 25 }
]
Enter fullscreen mode Exit fullscreen mode

Adding References

db.collection("users").findOne().then(r => {
    db.collection("products").insertOne({
        title: "A book to ODM in Nodejs",
        price: 200.99,
        added_by: r._id
    })
        .then(r => console.log(r.result))
        .catch(console.warn)
}).catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
{ n: 1, ok: 1 }
Enter fullscreen mode Exit fullscreen mode
db.collection("products").find().toArray()
    .then(console.log)
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
[
  {
    _id: 5e89ca3d78852a72f87479fb,
    title: 'A book to ODM in Nodejs',
    price: 200.99,
    added_by: 5e89a46778852a72f87479f9
  }
]
Enter fullscreen mode Exit fullscreen mode

Populating the User Data

db.collection("products").find().next()
    .then(r => {
        console.log("Book Title:", r.title)
        console.log("Price of Book:", r.price)
        db.collection("users").find({ _id: r.added_by }).next()
            .then(r => {
                console.log("Added By:", r.name)
            })
            .catch(console.warn)
    })
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
Book Title: A book to ODM in Nodejs
Price of Book: 200.99
Added By: Amit
Enter fullscreen mode Exit fullscreen mode

Mongoose: MongoDB ODM

Mongoose is an Object Document Mapping library for MongoDB in nodejs. This helps the nodejs developer to focus on data more than dealing with MongoDB. It allows the developers to define models with which they can interact with the database.

Installing Mongoose

# using npm
npm i mongoose

# using yarn
yarn add mongoose
Enter fullscreen mode Exit fullscreen mode
const mongoose = require("mongoose")
Enter fullscreen mode Exit fullscreen mode

Connecting to the DB

mongoose.connect("mongodb://localhost/test", {
    // settings are recommended by mongoose
    useUnifiedTopology: true, 
    useNewUrlParser: true,
    useFindAndModify: false
}).then(() => {
    console.log("Connected to DB")
}).catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
Connected to DB
Enter fullscreen mode Exit fullscreen mode

Creating Product Schema and Model

const {Schema, model} = require("mongoose")
Enter fullscreen mode Exit fullscreen mode
const ProductSchema = new Schema({
    title: String,
    price: Number,
    added_by: { type: Schema.Types.ObjectId, ref: "User" } // adding reference to User model via _id field
})

const Product = model("Product", ProductSchema)
Enter fullscreen mode Exit fullscreen mode

Creating User Schema and Model

const UserSchema = new Schema({
    name: String,
    email: String,
})

const User = model("User", UserSchema)
Enter fullscreen mode Exit fullscreen mode

Performing CRUD Operations

CREATE

let newProduct = new Product()
let newUser = new User()


newUser.name = "Dummy User"
newUser.email = "dummy@user.com"

newProduct.title = "A book on C Plus Plus";
newProduct.price = 200.99;
newProduct.added_by = newUser._id;
Enter fullscreen mode Exit fullscreen mode
5e89d1db8ccb5891c7c1d522
Enter fullscreen mode Exit fullscreen mode
newUser.save().then(r => {
    console.log("Added to new User to DB");
}).catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
Added to new User to DB
Enter fullscreen mode Exit fullscreen mode
newProduct.save().then(r => {
    console.log("Added to new Product to DB");
}).catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
Added to new Product to DB
Enter fullscreen mode Exit fullscreen mode

READ all the Data

User.find().then(r => {
    console.log(r)
}).catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
[
  {
    _id: 5e89d1db8ccb5891c7c1d522,
    name: 'Dummy User',
    email: 'dummy@user.com',
    __v: 0
  }
]
Enter fullscreen mode Exit fullscreen mode
Product.find().then(r => {
    console.log(r)
}).catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
[
  {
    _id: 5e89d1db8ccb5891c7c1d521,
    title: 'A book on C Plus Plus',
    price: 200.99,
    added_by: 5e89d1db8ccb5891c7c1d522,
    __v: 0
  }
]
Enter fullscreen mode Exit fullscreen mode

Populating the Reference

Product.find().populate("added_by").then(r => {
    console.log(r)
}).catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
[
  {
    _id: 5e89d1db8ccb5891c7c1d521,
    title: 'A book on C Plus Plus',
    price: 200.99,
    added_by: {
      _id: 5e89d1db8ccb5891c7c1d522,
      name: 'Dummy User',
      email: 'dummy@user.com',
      __v: 0
    },
    __v: 0
  }
]
Enter fullscreen mode Exit fullscreen mode

Populating the Reference and Projecting Specific Fields Only

Product.find().populate("added_by", {name: true}).then(r => {
    console.log(r)
}).catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
[
  {
    _id: 5e89d1db8ccb5891c7c1d521,
    title: 'A book on C Plus Plus',
    price: 200.99,
    added_by: { _id: 5e89d1db8ccb5891c7c1d522, name: 'Dummy User' },
    __v: 0
  }
]
Enter fullscreen mode Exit fullscreen mode

Finding By _id

Product.findById("5e89d1db8ccb5891c7c1d521")
    .then(r => console.log(r))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
{
  _id: 5e89d1db8ccb5891c7c1d521,
  title: 'A book on C Plus Plus',
  price: 200.99,
  added_by: 5e89d1db8ccb5891c7c1d522,
  __v: 0
}
Enter fullscreen mode Exit fullscreen mode

Fetch Single Result by non _id Field

Product.findOne({ price: { $gte: 100 } }) // finding one product whose price is greater than equal to 100
    .then(r => console.log(r))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
{
  _id: 5e89d01526491f916866e730,
  title: 'A book on C Plus Plus',
  price: 200.99,
  added_by: 5e89d01526491f916866e731,
  __v: 0
}
Enter fullscreen mode Exit fullscreen mode

UPDATE the Document

Product.findByIdAndUpdate("5e89d1db8ccb5891c7c1d521", { title:"C++ book" })
    .then(r => console.log(r))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
{
  _id: 5e89d1db8ccb5891c7c1d521,
  title: 'A book on C Plus Plus',
  price: 200.99,
  added_by: 5e89d1db8ccb5891c7c1d522,
  __v: 0
}
Enter fullscreen mode Exit fullscreen mode

You can also use the updateOne method to update the document.

Product.findById("5e89d1db8ccb5891c7c1d521")
    .then(r => console.log(r))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
{
  _id: 5e89d1db8ccb5891c7c1d521,
  title: 'C++ book',
  price: 200.99,
  added_by: 5e89d1db8ccb5891c7c1d522,
  __v: 0
}
Enter fullscreen mode Exit fullscreen mode

DELETE the Document

Product.findByIdAndDelete("5e89d1db8ccb5891c7c1d521")
    .then(r => console.log(r))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
{
  _id: 5e89d1db8ccb5891c7c1d521,
  title: 'C++ book',
  price: 200.99,
  added_by: 5e89d1db8ccb5891c7c1d522,
  __v: 0
}
Enter fullscreen mode Exit fullscreen mode

You can also use the deleteOne method to delete the document

Product.findById("5e89d1db8ccb5891c7c1d521")
    .then(r => console.log(r))
    .catch(console.warn)
Enter fullscreen mode Exit fullscreen mode
null
Enter fullscreen mode Exit fullscreen mode

To learn more on mongoose, follow this link to the documentation → https://mongoosejs.com/docs/guide.html

Top comments (0)