How to Code a Video Streaming Server using MongoDB
Tags: node, javascript, tutorial, mongodb
Published: 2020-11-28 02:21:00

---
title: How to Code a Video Streaming Server using MongoDB
published: true
description: Building point to make your own Netflix or YouTube app
tags: node, javascript, tutorial, mongodb
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/3urjjdfobn2orndod39u.png
---

Do you want to create a video streaming app and store videos in MongoDB? If you JUST want to learn about the streaming part, I made another (kind of successful) [post on it using purely NodeJS.](https://dev.to/abdisalan_js/how-to-code-a-video-streaming-server-using-nodejs-2o0)

BUT!

If you also want to know how to store your videos in MongoDB and stream them from there through NodeJS, this is the post for you!

## Final Result

![Buffing video of a bird](https://dev-to-uploads.s3.amazonaws.com/i/d01x8mfi44wdfkvmv6cr.png)

Just like the pure NodeJS solution, our final result will be a single HTML5 video that's streaming video from our server. Look at the grey bar in the timeline! That's buffering! 😃

If you want to git clone the project, here's the link to the repo [https://github.com/Abdisalan/blog-code-examples/tree/master/mongo-http-video](https://github.com/Abdisalan/blog-code-examples/tree/master/mongo-http-video)

## Easy Mode

If you have docker installed, you can use my docker compose file to run the project without needing to install any packages. You just need to run these docker compose commands as well as copy the `bigbuck.mp4` file from the `http-video-stream` folder to the `mongo-http-video` folder.

```bash
docker-compose up -d
# When you're done with it, you can tear it down using
docker-compose down -v
```

And the project will be running on `localhost:8000`

The rest of the article is instructions on how to build it from scratch. Enjoy!

## Part 1: MongoDB

MongoDB does not support Windows Subsystem for Linux (WSL), so you're better off using docker if you want to use WSL. Otherwise this should work in Windows just fine.

Install MongoDB, and if you're on windows these next commands (exe files) should be located in `C:\Program Files\MongoDB\Server\4.4\bin`

Open a terminal in that folder OR add it to your PATH and start the `mongod` process.

```bash
mongod
```

## Part 2: Setup Node Project

In another terminal, these commands will create a project folder and start your node project.

```bash
mkdir mongo-video-stream
cd mongo-video-stream
npm init
npm install --save express nodemon mongodb
```

## Part 3: index.html

We need to create an page with an HTML5 Video element and set the source to `"/mongo-video"` where our server will stream the video from mongoDB.

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>HTTP Video Stream From MongoDB</title>
  </head>
  <body>
    <video id="videoPlayer" width="650" controls muted="muted" autoplay>
      <source src="/mongo-video" type="video/mp4" />
    </video>
  </body>
</html>
```

## Part 4: Index.js

Lets setup our node server so that the root `"/"` endpoint serves our index.html page.

```javascript
const express = require("express");
const app = express();

app.get("/", function (req, res) {
  res.sendFile(__dirname + "/index.html");
});

app.listen(8000, function () {
  console.log("Listening on port 8000!");
});
```

## Part 5: package.json -- Run our server

Add a `start` script to your `package.json` so that we can run our server using `npm start` command.

```json
{
  "scripts": {
    "start": "nodemon index.js"
  }
}
```

Now you should be able to run `npm start`. Open your browser and go to `http://localhost:8000` to see if it worked!

![missing video](https://dev-to-uploads.s3.amazonaws.com/i/fj7fah22pgwdz7a6aiop.png)

## Midway Check In

How are you doing? Maybe drink some water, fix your posture, and relax your shoulders 😁

You're about to get to the good part!

## Part 6: index.js (Uploading)

We add an endpoint where we can upload a local video to mongodb. The video file I'm using is  `bigbuck.mp4` and can be found on my github at [https://github.com/Abdisalan/blog-code-examples/tree/master/http-video-stream](https://github.com/Abdisalan/blog-code-examples/tree/master/http-video-stream)

However you can use your own video file!

```javascript
const express = require("express");
const app = express();
const fs = require("fs");
const mongodb = require('mongodb');
const url = 'mongodb://localhost:27017';

app.get("/", function (req, res) {
  res.sendFile(__dirname + "/index.html");
});

// Sorry about this monstrosity -- just for demo purposes
app.get('/init-video', function (req, res) {
  mongodb.MongoClient.connect(url, function (error, client) {
    if (error) {
      res.json(error);
      return;
    }
    // connect to the videos database
    const db = client.db('videos');

    // Create GridFS bucket to upload a large file
    const bucket = new mongodb.GridFSBucket(db);

    // create upload stream using GridFS bucket
    const videoUploadStream = bucket.openUploadStream('bigbuck');

    // You can put your file instead of bigbuck.mp4
    const videoReadStream = fs.createReadStream('./bigbuck.mp4');

    // Finally Upload!
    videoReadStream.pipe(videoUploadStream);

    // All done!
    res.status(200).send("Done...");
  });
});

app.listen(8000, function () {
  console.log("Listening on port 8000!");
});
```

After saving the index.js file, your server should restart (because we're using nodemon). Once you have the video ready, you can go to `localhost:8000/init-video` in your browser and it should have uploaded your local file to mongodb!

**Almost there!**

If you want to double check that the file was uploaded, open another terminal and connect to mongodb.

```bash
mongo
```

Then go to the videos database and count the number of documents in the `fs.files` collection by GridFS.

```bash
use videos
db.fs.files.count()
```

The count should be how many times you went to `localhost:8000/init-video` because it uploads our video file every time you load `/init-video`.

## Part 7: index.js (Streaming)

Lastly, we're gonna add the `/mongo-video` endpoint to stream our video!

```javascript
app.get("/mongo-video", function (req, res) {
  mongodb.MongoClient.connect(url, function (error, client) {
    if (error) {
      res.status(500).json(error);
      return;
    }
		
    // Check for range headers to find our start time
    const range = req.headers.range;
    if (!range) {
      res.status(400).send("Requires Range header");
    }

    const db = client.db('videos');
    // GridFS Collection
    db.collection('fs.files').findOne({}, (err, video) => {
      if (!video) {
        res.status(404).send("No video uploaded!");
        return;
      }

      // Create response headers
      const videoSize = video.length;
      const start = Number(range.replace(/\D/g, ""));
      const end = videoSize - 1;

      const contentLength = end - start + 1;
      const headers = {
        "Content-Range": `bytes ${start}-${end}/${videoSize}`,
        "Accept-Ranges": "bytes",
        "Content-Length": contentLength,
        "Content-Type": "video/mp4",
      };

      // HTTP Status 206 for Partial Content
      res.writeHead(206, headers);

      // Get the bucket and download stream from GridFS
      const bucket = new mongodb.GridFSBucket(db);
      const downloadStream = bucket.openDownloadStreamByName('bigbuck', {
        start
      });

      // Finally pipe video to response
      downloadStream.pipe(res);
    });
  });
});
```

Save the file and go to `localhost:8000` one more time and the video should be streaming!

## Conclusion

With this, you can make your own basic YouTube or Netflix app!

For an in-depth line by line explanation with theory on how this works, [consider watching my YouTube video.](https://youtu.be/y6Z-SZt-Xvw)

This was a basic overview of how to get this working, if you want any in-depth blog posts on any of these topics (mongodb, streaming theory), feel free to comment down below!

Happy Streaming! ✌

### Disclaimer
You probably shouldn't use this in production because its not the most optimized architecture 😋