loading...
Cover image for MongoDB without Mongoose

MongoDB without Mongoose

kamalhossain profile image Kamal Hossain ・5 min read

Lets suppose you just want to store a bunch of email addresses as your subscribers in your MongoDB database. Nothing else.

There is no need to implement an entire driver to handle this. Yes, of course, drivers provide many advantages to make our lives easy. But to keep things simple and lightweight we can use only MongoDB for CRUD operation without a mongoose.

What about validation? Don't worry, packages like sanitize-html can be used in MongoDB to validate data before storing to a database.

Get the Source code if you don't want to follow along.

Let's get started.


Create a nodejs Server

Run the followings in your terminal:

mkdir mongodb-without-mongoose && cd mongodb-without-mongoose

These will create a folder called mongodb-without-mongoose and navigate to the folder.

npm init -y && npm install express mongodb --save

To initialize package.json file in our source folder to install dependencies, we run the first part of the command. And the second part is for installing the express.js and MongoDB as our dependencies.

Now let's create an app.js file in your project folder. And fill the file with the followings to create a simple server:

const express = require('express')
const mongodb = require('mongodb')

const app = express()
let db

const PORT = 5000

app.get('/testRoute', (req, res) => res.end('Hello from Server!'))

app.listen(PORT, () => {
  console.log(`Node.js App running on port ${PORT}...`)
})

To start the server run:

node app.js

Here we have just created a simple server at port 5000. On localhost:5000/testRoute it will send the response, Hello from Server!.


Connect to mongodb from server

In this example, we are going to connect the local MongoDB of windows. We are not going to any cloud services of MongoDB. So let's add some lines in our app.js to establish the connection.

// ...
const app = express()
let db

let connectionString = `mongodb://localhost:27017/crud`

This is the default connection string of windows to connect to the local database. Now let us connect to MongoDB by using this string.

// ...
const app = express()
let db

let connectionString = `mongodb://localhost:27017/crud`

mongodb.connect(
  connectionString,
  { useNewUrlParser: true, useUnifiedTopology: true },
  function (err, client) {
    db = client.db()
    app.listen(5000)
  }
)

Here above the MongoDB.connect() taking the connection string as the first argument, after that a second argument is an object for not getting the deprecation warnings from MongoDB.
And finally, the last argument is the callback function which can be used after MongoDB.connect() function trying to connect to MongoDB.

In our case, we are storing the database in a variable for further use and also started the app for listening in port 5000.

Now that we have our database connected, let's create some endpoints to make the app useful.

// ...

mongodb.connect(
  connectionString,
  { useNewUrlParser: true, useUnifiedTopology: true },
  function (err, client) {
    db = client.db()
    app.listen(5000)
  }
)

app.post('/create-data', function (req, res) {
  // Sending request to create a data
  db.collection('data').insertOne({ text: req.body.text }, function (
    err,
    info
  ) {
    res.json(info.ops[0])
  })
})

Here we have set up a post request to our app to /create-data. Here we are using the db.collection() to specify the collection name in the crud database that we have connected already.

In this method, we are chaining the insertOne() to create a document in the collection. We are passing two arguments in this function.

The first one is the text property with the string from the req.body object. And the second one is the callback function to do some stuff when the insetOne() method tries to insert the document to the collection.

In our callback function, we have two arguments, err and info. We are going to retrieve our collection of documents from info.ops[0] and then simply send back the response to the requested user.

Let's try a post request on localhost:5000/create-data with the following json data from postman.

{
  "text": "Kamal Hossain"
}

What have got?

Well, I have got a 500 Internal Server Error with a bunch of HTML values in response. So let's check the console where is server is running.

TypeError: Cannot read property 'text' of undefined

I have got some lines in our console and the first line is telling this above. So why this is happening?

Well, we have sent JSON data to our nodejs app, where the server was created with the help of express.js. So by default, it can't read any JSON Object from incoming requests. So we have to add a line for that.

// ...

mongodb.connect(
  connectionString,
  { useNewUrlParser: true, useUnifiedTopology: true },
  function (err, client) {
    db = client.db()
    app.listen(5000)
  }
)

app.use(express.json())

This will take care of the current problem. Let's save & restart our server. Then send the request again.

{
  "text": "Kamal Hossain",
  "_id": "5f5c27353c14cc09309d4440"
}

This is the response I have got from our server. Which was sent from the insertOne() methods callback function. The _id is the unique id to identify our this particular document across the database.

Now that we have created our first document lets create a route to get all the documents from our collection via get request.

// ...

app.post('/create-data', function (req, res) {
  // Sending request to create a data
  db.collection('data').insertOne({ text: req.body.text }, function (
    err,
    info
  ) {
    res.json(info.ops[0])
  })
})

app.get('/', function (req, res) {
  // getting all the data
  db.collection('data')
    .find()
    .toArray(function (err, items) {
      res.send(items)
    })
})

Here we are setting the route as / which will be the root route of any domain. In our case the localhost:5000. Here we are using the find() method to get all the documents from the collection. Lastly, we are chaining the toArray() method to put all the documents in an array, and in the callback of toArray() we are sending the response back.

Lets do a get request in postman to localhost:5000/

[
    {
        "_id": "5f5c27353c14cc09309d4440",
        "text": "Kamal Hossain"
    }
]

Now let's add two more routes in our app to update and delete a document.

// ...

app.get('/', function (req, res) {
  // getting all the data
  db.collection('data')
    .find()
    .toArray(function (err, items) {
      res.send(items)
    })
})

app.put('/update-data', function (req, res) {
  // updating a data by it's ID and new value
  db.collection('data').findOneAndUpdate(
    { _id: new mongodb.ObjectId(req.body.id) },
    { $set: { text: req.body.text } },
    function () {
      res.send('Success updated!')
    }
  )
})

In our /update-data route are are mainly updating a document by findOneAndUpdate(). In this method we are passing the object Id that needs to be updated, then we are passing the updated text. And lastly, we are just sending the success response.

Let's now delete a document.

// ...

app.put('/update-data', function (req, res) {
  // updating a data by it's ID and new value
  db.collection('data').findOneAndUpdate(
    { _id: new mongodb.ObjectId(req.body.id) },
    { $set: { text: req.body.text } },
    function () {
      res.send('Success updated!')
    }
  )
})

app.delete('/delete-data', function (req, res) {
  // deleting a data by it's ID
  db.collection('data').deleteOne(
    { _id: new mongodb.ObjectId(req.body.id) },
    function () {
      res.send('Successfully deleted!')
    }
  )
})

In our delete-data route we are using delete() method to delete the document from collection. And lastly sending a response to the client in the callback function.


Originally published at https://kamalhossain.me/blog/mongodb-without-mongoose

Posted on by:

kamalhossain profile

Kamal Hossain

@kamalhossain

Full Stack Web Developer who is mostly relying on JavaScript for now.

Discussion

markdown guide