Restaurant Recommendation using MERN

Last Updated : 23 Jul, 2025

This article is about Restaurant Recommendations using the MERN (MongoDB, Express.js, React.js, Node.js) stack. This project displays a list of restaurants to the users. Users can apply filters like location, cuisines, and ratings based on filters applied by the user, the user gets recommended specific restaurants.

Output Preview:

Prerequisites:

Functionalities of Restaurant Recommendation

  • Get All Restaurants data: Initially user can see all the list of restaurants which present in the database.
  • Location: User can select a location from the location dropdown.Based on the location selected by the user , list of restaurants gets changed. User can only the restaurants that contains the location selected by the user.
  • Cuisines: User can select a cuisine from the Cuisines dropdown.Based on the selected cuisines the list gets updated.
  • Rating: User can select a rating such as above 3 and above 4. If user selects above 3 then user gets list of restaurants above 3 rating and same goes for above 4.

Approach:

  • In Frontend, We have used two components Navbar which contains the name of the title and Card component which contains the UI of the restaurant details.I have used custom hook useRestaurantContext which contains the details of the filters selected by the users.
  • In Backend, i have created one api route /api/restaurants which gets all the restaurants data from the database and if we pass locatin, rating and cuisines data in the request body then it gets the data from the database based on filters.

Frontend

In Frontend, i have used two components Navbar which contains the name of the title and Card component which contains the UI of the restaurant details.I have used custom hook useRestaurantContext which contains the details of the filters selected by the users.

Steps to Setup the Frontend Project

Step 1: Create a reactJS application by using this command

npx create-react-app myapp

Step 2: Navigate to project directory

cd myapp

Step 3: Install the necessary packages/libraries in your project using the following commands.

npm i axios react-bootstrap

Project Structure:

frontend-screenshot
Frontend Project Structure

The updated dependencies in package.json file will look like:

"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.5.1",
"bootstrap": "^5.3.2",
"react": "^18.2.0",
"react-bootstrap": "^2.9.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}

Explanation

  • App.js : This is the main file which contains the Navabar component ,filters like location,rating,cuisines and CardItem component which contains the information of each restaurant in card format.
  • NavBar.js : This file contain the navbar which has the name of the project.
  • CardItem : This file contains the code to fetch the restaurant data from the backend based on the filters selected by the user and present the each restaurant details to the user in card format.
  • useContext.js : This file contains the context api code where the filters like location,rating and cuisines are accessed as global state.
  • useRestaurant.js : This file contains the code for the custom hook which is used to access the state of location,rating,cuisines at any component in the project.

Example: Implementation to design the frontend part of the Restaurant Recommendation.

CSS
/* App.module.css */

.headers {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-left: 5vw;
    margin-right: 5vw;
    margin-top: 3vh;
    padding-bottom: 2vh;
    border-bottom: 1px solid gray;
}

.locationContainer {
    width: 10vw;
}

.cuisinesContainer {
    margin-top: 5vh;
    width: 15vw;
    height: 10vh;
    overflow-y: scroll;
}

.ratingContainer {
    width: 10vw;
}

.restaurants {
    padding-bottom: 3vh;
}

.restaurants h3 {
    margin-left: 5vw;
    margin-top: 1vh;
    margin-bottom: 1vh;
}
JavaScript
// App.js

import style from "./App.module.css";
import { Form } from "react-bootstrap";
import NavBar from "./components/NavBar/NavBar";
import { useState } from "react";
import CardItem from "./components/RestaurantCard/Card";
import useRestaurantContext from "./components/Hooks/useRestaurant";

function App() {


    const { selectedItems, setSelectedItems, setLocation, setRating } =
        useRestaurantContext();

    const options = [
        { value: "North Indian", label: "North Indian" },
        { value: "South Indian", label: "South Indian" },
        { value: "Chinese", label: "Chinese" },
        { value: "Desserts", label: "Desserts" },
        { value: "Italian", label: "Italian" },
        { value: "Oriental", label: "Oriental" },
        { value: "Pastas", label: "Pastas" },
        { value: "Pizzas", label: "Pizzas" },
        { value: "Japanese", label: "Japanese" },
        { value: "Sushi", label: "Sushi" },
        { value: "Barbecue", label: "Barbecue" },
        { value: "Steak", label: "Steak" },
        { value: "Seafood", label: "Seafood" },
    ];

    const handleCheckboxChange = (value) => {

        if (selectedItems.includes(value)) {

            setSelectedItems(selectedItems.filter((item) => item !== value));
        } else {

            setSelectedItems([...selectedItems, value]);
        }

        console.log("elements", selectedItems);
    };

    return (
        <div className="App">
            <NavBar />
            <div>
                <div className={style.headers}>
                    <div className={style.locationContainer}>
                        <Form.Select
                            aria-label="Location"
                            onChange={(e) => {
                                setLocation(e.target.value);
                            }}
                        >
                            <option hidden>Select Location</option>
                            <option value="Hyderabad">Hyderabad</option>
                            <option value="Banglore">Banglore</option>
                            <option value="Mumbai">Mumbai</option>
                            <option value="Delhi">Delhi</option>
                            <option value="Pune">Pune</option>
                            <option value="Chennai">Chennai</option>
                        </Form.Select>
                    </div>
                    <div className={style.cuisinesContainer}>
                        <Form>
                            <Form.Label>Select Cuisines:</Form.Label>
                            {options.map((option) => (
                                <Form.Check
                                    key={option.value}
                                    type="checkbox"
                                    id={option.value}
                                    label={option.label}
                                    checked={selectedItems?.includes(option.value)}
                                    onChange={() => handleCheckboxChange(option.value)}
                                />
                            ))}
                        </Form>
                    </div>
                    <div className={style.ratingContainer}>
                        <Form.Select
                            aria-label="Default select example"
                            onChange={(e) => {
                                setRating(e.target.value);
                            }}
                        >
                            <option hidden>Select Rating</option>
                            <option value="3">3 above</option>
                            <option value="4">4 above</option>
                        </Form.Select>
                    </div>
                </div>
            </div>
            <div className={style.restaurants}>
                <h3>Restaurants</h3>
                <CardItem />
            </div>
        </div>
    );
}

export default App;
JavaScript
// NavBar.js

import React from "react";
import { Nav, Navbar, Container } from "react-bootstrap";

export default function NavBar() {
    return (
        <div>
            <Navbar bg="dark" data-bs-theme="dark">
                <Container>
                    <Navbar.Brand href="#home">
                        Restro - find your restaurant
                    </Navbar.Brand>
                    <Nav className="me-auto"></Nav>
                </Container>
            </Navbar>
        </div>
    );
}
JavaScript
// Card.js

import Card from "react-bootstrap/Card";
import ListGroup from "react-bootstrap/ListGroup";
import useRestaurantContext from "../Hooks/useRestaurant";
import { useEffect, useState } from "react";
import axios from "axios";

function CardItem() {
    const { location, rating, selectedItems } = useRestaurantContext();
    const [restaurants, setRestaurants] = useState([]);

    useEffect(() => {
        getAllRestaurants();
    }, [location, rating, selectedItems]);

    const getAllRestaurants = async () => {
        axios
            .post("http://localhost:4000/api/restaurants", {
                location: location,
                rating: rating,
                cuisines: selectedItems,
            })
            .then(
                (response) => {
                    console.log("response is", response);
                    if (response.data.success) {
                        setRestaurants(response.data.data);
                    }
                },
                (error) => {
                    console.log("error is ", error);
                }
            );
    };

    return (
        <div style={{ display: "flex", flexWrap: "wrap", marginLeft: "2vw" }}>
            {restaurants.map((item) => (
                <Card style={{ width: "18rem", marginLeft: "4vw", marginTop: "4vh" }}>
                    <Card.Img
                        variant="top"
                        src={item.image}
                        style={{ height: "20vh", backgroundCover: "cover" }}
                    />
                    <Card.Body>
                        <Card.Title>{item.name}</Card.Title>
                        <Card.Text>
                            Types of food we offer :{" "}
                            {item.cuisines?.map((foodItem) => foodItem + ",  ")}
                        </Card.Text>
                    </Card.Body>
                    <ListGroup className="list-group-flush">
                        <ListGroup.Item>Address:{item.address}</ListGroup.Item>
                        <ListGroup.Item>City:{item.location}</ListGroup.Item>
                        <ListGroup.Item>Rating:{item.rating}</ListGroup.Item>
                    </ListGroup>
                </Card>
            ))}
        </div>
    );
}

export default CardItem;
JavaScript
// useContext.js

import { createContext, useContext, useState } from "react";

const RestaurantContext = createContext();

const Provider = ({ children }) => {
    const [selectedItems, setSelectedItems] = useState([]);
    const [location, setLocation] = useState();
    const [rating, setRating] = useState();

    const data = {
        selectedItems,
        setSelectedItems,
        location,
        setLocation,
        rating,
        setRating,
    };

    return (
        <RestaurantContext.Provider value={{ selectedItems, setSelectedItems }}>
            {children}
        </RestaurantContext.Provider>
    );
};

export { Provider };

export default RestaurantContext;
JavaScript
// useRestaurant.js
import React, { useContext } from 'react';
import { RestaurantContext } from '../Context/RestaurantContext'; // Import the correct context

const useRestaurantContext = () => {
    const restaurantContext = useContext(RestaurantContext);

    if (!restaurantContext) {
        // Handle missing context (optional)
        throw new Error('RestaurantContext not found');
    }

    return restaurantContext;
};

export default useRestaurantContext;

Step to Run Application: Run the application using the following command from the root directory of the project

npm start

Output: Your project will be shown in the URL http://localhost:3000/

Backend

In Backend, i have created one api route /api/restaurants which gets all the restaurants data from the database and if we pass locatin, rating and cuisines data in the request body then it gets the data from the database based on filters.

Steps to Setup the Backend of Application

Step 1: Create seperate directories for frontend and backend

mkdir backend

Step 2: Navigate to the backend directory using the command

cd backend

Step 3: Initialize Node Package Manager using the command.

npm init -y

Step 5: Install express, cors, body-parser, dotenv, mongoose packages using following command.

npm i express cores body-parser mongoose dotenv

Note: In backend create a file named .env and add variable

PORT = 4000 and MONGO_URL = specifiy your mongodb url connection.

Project Structure:

backend-structure
Backend Project Structure

The updated dependencies in package.json file for backend will look like:

"dependencies": {
"bcrypt":"^5.1.1"
"cors": "^2.8.5",
"express": "^4.18.2",
"mongoose": "^8.0.0",
"nodemon": "^3.0.1",
}

Explanation

  • index.js : This file contains the main code which involves connecting to mongodb database and calling apis.
  • Restaurant.model.js : This file contains the schema design of restaurant model.
  • restaurant.route.js : This file contains the code for the api route to fetch the data from the database based on filters applied by the user.
  • restaurant.controller.js : This file contains the code for the api route to fetch the data from the database.

Example: Implementation to design the backend part of Restaurant Recommendation.

JavaScript
// index.js

const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');

const cors = require('cors');

require('dotenv').config();

// create a express app
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors());

// Connect to mongodb using mongoose

// Please use process.env.MONGO_URL instead of my mongodb url
mongoose
    .connect(YOURS_URI, {
        useNewUrlParser: true,
        useUnifiedTopology: true,
    })
    .then(() => {
        console.log('Connected to MongoDB');
    })
    .catch((error) => {
        console.log('Failed to connect to MongoDB', error);
    });

app.get('/health', (req, res) => {
    res.status(200).json('Server is up and running');
});

// Start server
const PORT = process.env.PORT || 4000;
app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});

const restaurantRoutes = require('./routes/restaurant.route');

app.use('/api', restaurantRoutes);
JavaScript
// Restaurant.model.js
const mongoose = require('mongoose');

const restaurantSchema = new mongoose.Schema({
  name: String,
  address: String,
  contact: String,
  location: String,
  rating: Number,
  offers: Boolean,
  cuisines: [String],
  image: String,
});

module.exports = mongoose.model('restaurant', restaurantSchema);
JavaScript
//restaurant.route.js

const express = require('express');
const router = express.Router();

const {
  getRestaurantsByFilters,
} = require('../controllers/restaurant.controller');

router.route('/restaurants').post(getRestaurantsByFilters);

module.exports = router;
JavaScript
// restaurant.controller.js

const RestaurantModel = require('../models/Restaurant.model');

const getRestaurantsByFilters = async (req, res) => {
  console.log('request body is', req.body);
  try {
    const { location, rating, cuisines } = req.body;
    const query = {};
    if (location) {
      query.location = location;
    }

    if (rating?.length > 0) {
      if (rating == 3) {
        query.rating = { $gte: 3, $lte: 5 };
      } else {
        query.rating = { $gte: 4, $lte: 5 };
      }
    }

    if (cuisines?.length > 0) {
      query.cuisines = { $in: cuisines };
    }

    const restaurants = await RestaurantModel.find(query);
    if (restaurants.length > 0) {
      res.json({ success: true, data: restaurants });
    } else {
      res.json({ success: false, message: 'No such data found!' });
    }
  } catch (error) {
    res.json({ success: false, error: error.message });
  }
};

module.exports = { getAllRestaurants, getRestaurantsByFilters };

Step to Run Application: Run the application using the following command from the root directory of the project

npm start

Output:

Comment

Explore