Caching Implemented in Express JS

Caching Implemented in Express JS

Imagine you’re running a popular online store. Your store has thousands of products, and each product has its own page with details like its name, price, description, and customer reviews. These details are stored in a database.

Now, let’s say a particular product, let’s call it “Product X”, is currently trending. Thousands of users are visiting the product page for Product X every minute. Each time a user visits the page, your server has to query the database to fetch the product details. This can put a significant load on your database and slow down the response time for the user.

Here’s where caching comes to the rescue! 🦸

Instead of querying the database every time, you can store the product details for Product X in a cache after the first query. For subsequent requests, instead of hitting the database, your server can fetch the product details from the cache. This is much faster because accessing a cache is quicker than querying a database, especially if the database is not located on the same machine as your server.

This is all about real-world example, now see in Action.

(NOT THINK ABOUT HOW IT IS IMPLEMENTED. We Will See it...)

Here Server is running and db is connected.

User Request for data 1st Time from server.

it take around 72-102 ms time. Here same thing happened in backend when 1st request is goes to server.

  • server execute query.

  • store the data in cache.

  • response the data.

2nd request come from different user for same thing

  • server check data in cache

  • cache have response for that.

  • serve take response from cache and response to client.

Database I/O operation take much time compare to response the data from cache. Here Below image show that thing.

What is Cache?

Cache is a small memory, fast access local store where we store frequently accessed data.

What is Caching?

Caching is the technique of storing copies of frequently used application data in a layer of smaller, faster memory in order to improve data retrieval times, throughput, and compute costs.

Why do we use Cache?

Cache is based on the principle of locality. It means that frequently accessed data is kept close to the system. The two kinds of locality are:

  • Temporal locality, where data that has been referenced recently is likely to be referenced again (i.e. time-based locality).
    It repeatedly refers to same data in short time span.

  • Spatial locality, where data that is stored near recently referenced data is also likely to be referenced again(i.e. space-based locality)
    It only refers to data item which are closed together in memory. eg. Data stored together in an array

How does a Cache work?

When a request comes to a system, there can be two scenarios. If a copy of the data exists in cache it’s called a cache hit, and when the data has to be fetched from the primary data store it’s called a cache miss. The performance of a cache is measured by the number of cache hits out of the total number of requests.

Implementation

Requirements

  1. Node JS

  2. MongoDB Server

File Structure

Packages Require:

"dependencies": {
        "express": "^4.19.2",
        "mongoose": "^8.4.0",
        "nodemon": "^3.1.0",
        "pg": "^8.11.5"
 }

indexmongodb.js

const express = require('express');
const mongoose = require('mongoose');
const app = express();
const port = 3000;

let cache = {};

// Connection URL
const url = 'mongodb://127.0.0.1:27017/college';

// Connect to the database
mongoose.connect(url).then(res => {
    console.log("Connected DB.")
}).catch(err => {
    console.error(err);
});


// Define schema and model
const studentSchema = new mongoose.Schema({}, { collection: 'student' });
const Student = mongoose.model('Student', studentSchema);

// Function to fetch data from the database
const fetchDataFromDB = async () => {
    try {
        const data = await Student.find();
        return data;
    } catch (err) {
        console.error(err);
    }
};

app.get('/data', async (req, res) => {
    const key = '/data';
    let start = Date.now();

// Check data in cache. if exist then return it.
    if (cache[key]) {
        console.log('Returning data from cache');
        console.log(`Time taken: ${Date.now() - start} ms`);
        return res.send(cache[key]);
    }

// if data not present in cache then trigger db for data.
    try {
        const result = await fetchDataFromDB();
        cache[key] = result; // Cache the data
        console.log('Data fetched from DB and cached');
        console.log(`Time taken: ${Date.now() - start} ms`);
        return res.send(result);
    } catch (err) {
        console.error(err);
        res.status(500).send('Server error');
    }
});

app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}`);
});
  1. const express = require('express'); - This line is importing the Express.js library, which is a popular web application framework for Node.js.

  2. const mongoose = require('mongoose'); - Here, we’re importing Mongoose, a MongoDB object modeling tool designed to work in an asynchronous environment.

  3. const app = express(); - This line creates an instance of an Express application.

  4. const port = 3000; - We’re setting the port number where our server will be listening.

  5. let cache = {}; - Here, we’re creating an empty JavaScript object that will be used as a cache.

  6. const url = 'mongodb://127.0.0.1:27017/college'; - This is the URL for connecting to the MongoDB database. The database is named ‘college’.

  7. mongoose.connect(url).then(res => {...}).catch(err => {...}); - This line connects to the MongoDB database using the provided URL. If the connection is successful, it logs “Connected DB.” If there’s an error, it logs the error.

  8. const studentSchema = new mongoose.Schema({}, { collection: 'student' }); - Here, we’re defining a Mongoose schema for the ‘student’ collection in the database.

  9. const Student = mongoose.model('Student', studentSchema); - This line creates a Mongoose model from the schema. We can use this model to interact with the ‘student’ collection in the database.

  10. const fetchDataFromDB = async () => {...}; - This is an asynchronous function that fetches data from the ‘student’ collection in the database.

  11. app.get('/data', async (req, res) => {...}); - This sets up a route handler for GET requests to the ‘/data’ endpoint. If the data is in the cache, it returns the cached data. If not, it fetches the data from the database, caches it, and then returns it.

  12. app.listen(port, () => {...}); - Finally, this line starts the server and makes it listen for requests on the specified port.

Check Out Video of Implementation

CachingNode Zip