diff --git a/models/NetflixTitle.js b/models/NetflixTitle.js new file mode 100644 index 000000000..19a530637 --- /dev/null +++ b/models/NetflixTitle.js @@ -0,0 +1,16 @@ +import mongoose from "mongoose"; + +const NetflixTitleSchema = new mongoose.Schema({ + title: String, + director: String, + cast: [String], + country: String, + date_added: String, + release_year: Number, + rating: String, + duration: String, + genres: [String], + description: String, +}); + +export const NetflixTitle = mongoose.model("NetflixTitle", NetflixTitleSchema); \ No newline at end of file diff --git a/package.json b/package.json index 6830a48aa..04cbb9d1e 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", "cors": "^2.8.5", + "dotenv": "^16.4.7", "express": "^4.17.3", "mongoose": "^8.0.0", "nodemon": "^3.0.1" diff --git a/routes/netflixRoutes.js b/routes/netflixRoutes.js new file mode 100644 index 000000000..f0595fbaa --- /dev/null +++ b/routes/netflixRoutes.js @@ -0,0 +1,67 @@ +import express from "express"; +import { NetflixTitle } from "../models/NetflixTitle.js"; + +const router = express.Router(); + +/**Fetch all Netflix titles with optional filters, pagination & sorting*/ +router.get("/", async (req, res) => { + const { country, genre, year, page = 1, limit = 10, sort } = req.query; + let query = {}; + + // Filtering options + if (country) query.country = new RegExp(country, "i"); // Case-insensitive country search + if (genre) query.genres = { $in: [new RegExp(genre, "i")] }; // Match genre inside array + if (year) query.release_year = Number(year); // Convert year to number + + const options = { + skip: (page - 1) * limit, // Pagination logic + limit: Number(limit), + }; + + // Sorting options + if (sort === "asc") options.sort = { title: 1 }; // Sort A-Z + if (sort === "desc") options.sort = { title: -1 }; // Sort Z-A + + try { + const titles = await NetflixTitle.find(query, null, options); + const totalCount = await NetflixTitle.countDocuments(query); + + res.json({ + totalResults: totalCount, + currentPage: Number(page), + totalPages: Math.ceil(totalCount / limit), + results: titles, + }); + } catch (error) { + res.status(500).json({ error: "Could not fetch data" }); + } +}); + +/* Fetch a single Netflix title by ID*/ +router.get("/:id", async (req, res) => { + try { + const title = await NetflixTitle.findById(req.params.id); + if (!title) { + return res.status(404).json({ error: "Title not found" }); + } + res.json(title); + } catch (error) { + res.status(500).json({ error: "Invalid ID format" }); + } +}); + +/** Get Netflix genre statistics (count of titles per genre)*/ +router.get("/stats/genres", async (req, res) => { + try { + const stats = await NetflixTitle.aggregate([ + { $unwind: "$genres" }, // Splits multiple genres into separate entries + { $group: { _id: "$genres", count: { $sum: 1 } } }, // Count occurrences per genre + { $sort: { count: -1 } } // Sort by most common genres + ]); + res.json(stats); + } catch (error) { + res.status(500).json({ error: "Could not fetch genre statistics" }); + } +}); + +export default router; \ No newline at end of file diff --git a/server.js b/server.js index 647e7b144..8b4c655d8 100644 --- a/server.js +++ b/server.js @@ -1,35 +1,77 @@ import express from "express"; import cors from "cors"; import mongoose from "mongoose"; +import dotenv from "dotenv"; +import netflixData from "./data/netflix-titles.json"; +import { NetflixTitle } from "./models/NetflixTitle.js"; +import netflixRoutes from "./routes/netflixRoutes.js"; -// If you're using one of our datasets, uncomment the appropriate import below -// to get started! -// import avocadoSalesData from "./data/avocado-sales.json"; -// import booksData from "./data/books.json"; -// import goldenGlobesData from "./data/golden-globes.json"; -// import netflixData from "./data/netflix-titles.json"; -// import topMusicData from "./data/top-music.json"; +dotenv.config(); const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/project-mongo"; -mongoose.connect(mongoUrl); +mongoose.connect(mongoUrl, { useNewUrlParser: true, useUnifiedTopology: true }); mongoose.Promise = Promise; -// Defines the port the app will run on. Defaults to 8080, but can be overridden -// when starting the server. Example command to overwrite PORT env variable value: -// PORT=9000 npm start const port = process.env.PORT || 8080; const app = express(); -// Add middlewares to enable cors and json body parsing +// Database Seeding +if (process.env.RESET_DB) { + const seedDatabase = async () => { + console.log("⏳ Resetting database..."); + + try { + await NetflixTitle.deleteMany({}); // Clear existing data + + // Transform "listed_in" into "genres" (array instead of string) + const formattedData = netflixData.map((item) => ({ + show_id: item.show_id, + title: item.title, + director: item.director, + cast: item.cast ? item.cast.split(", ") : [], // Convert string to array + country: item.country, + date_added: item.date_added, + release_year: item.release_year, + rating: item.rating, + duration: item.duration, + genres: item.listed_in ? item.listed_in.split(", ") : [], // Convert string to array + description: item.description, + type: item.type + })); + + // Insert the formatted data + const insertedMovies = await NetflixTitle.insertMany(formattedData); + console.log(` Database seeded successfully! ${insertedMovies.length} movies added.`); + } catch (error) { + console.error(" Error seeding database:", error); + } + }; + + seedDatabase(); +} + +// Middleware app.use(cors()); app.use(express.json()); -// Start defining your routes here +// API Documentation app.get("/", (req, res) => { - res.send("Hello Technigo!"); + res.json({ + message: "Welcome to the Netflix API!", + endpoints: { + allTitles: "/netflix", + singleTitle: "/netflix/:id", + filterByCountry: "/netflix?country=Sweden", + filterByGenre: "/netflix?genre=Comedy", + filterByYear: "/netflix?year=2020", + }, + }); }); -// Start the server +// Use Routes +app.use("/netflix", netflixRoutes); + +// Start the Server app.listen(port, () => { - console.log(`Server running on http://localhost:${port}`); -}); + console.log(`🚀 Server running on http://localhost:${port}`); +}); \ No newline at end of file