From f67d9e38dd66b27796ffd3c2275f4ea02933a58b Mon Sep 17 00:00:00 2001 From: Akbhartiq Date: Sat, 23 Mar 2024 15:00:27 +0530 Subject: [PATCH] Movie-Filter Api Done --- .env | 2 +- controllers/movie_filter.js | 135 ++++++++++++++++++++++++++++++++ index.js | 9 +++ package-lock.json | 22 ++++-- package.json | 3 +- prisma/schema.prisma | 149 ++++++++++++++++++------------------ routes/movie_filter.js | 17 ++++ 7 files changed, 253 insertions(+), 84 deletions(-) create mode 100644 controllers/movie_filter.js create mode 100644 routes/movie_filter.js diff --git a/.env b/.env index b7e7129..fe43885 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ -DATABASE_URL="mongodb+srv://Admin:Admin@learningcluster.iiwtmxs.mongodb.net/sample_mflix?retryWrites=true&w=majority&appName=LearningCluster" +DATABASE_URL="mongodb+srv://testuser:test1234@moviewebsite.hurxgdw.mongodb.net/sample_mflix?retryWrites=true&w=majority&appName=moviewebsite" JWT_SECRET="ac6043c6817f9de65a2dd031de14f6ee7a89b1f8c18631f6aba66664a075430b" \ No newline at end of file diff --git a/controllers/movie_filter.js b/controllers/movie_filter.js new file mode 100644 index 0000000..4edb1a8 --- /dev/null +++ b/controllers/movie_filter.js @@ -0,0 +1,135 @@ +// import asynchHandler(perhaps i didn't used it) +const asyncHandler = require("express-async-handler"); + +// import prisma to connect with mongo-db +const prisma = require("../prisma/index"); + + + +// global variables to trace the total number of movies and pages to be there +var total_number_of_movies = 0;//by def 0 +var total_number_of_pages = 0;//by def 0 + + +// let's write a function which returns us the total number of the movies found + +const total_No_Of_Movies = async (lang, genre) => { + + // define the prisma query + const moviesQuery = { + // add genre if genre is not undefined , and same for language(lang) + where: { + ...(genre && { + genres: { + hasSome: [genre], + } + }), + ...(lang && { + languages: { + hasSome: [lang] + } + }) + }, + }; + + // search in the database + const movies = await prisma.embedded_movies.findMany(moviesQuery); + + // finally return the total number of the movies + console.log("The total_global count of such movies is ", movies.length); + return movies.length; +} + +// let's create the getAllMovies function for the router + +const getAllMovies = async (req, res) => { + try { + // Extract query parameters from the request + const { page, lang, genre } = req.query; + + // declare the page_size_variable + const page_size = 10; + + + // if page is 1 , call the function and fill the global values such as total_number of movies and pages + if (page == 1) { + + // It is the first time, so call it and wait it until its finishes its execution + total_number_of_movies = await total_No_Of_Movies(lang, genre); + + // get the toal number of pages + let flag = Math.floor(total_number_of_movies / page_size); + + if (flag * page_size == total_number_of_movies) { + total_number_of_pages = flag; + } + else { + total_number_of_pages = flag + 1; + } + } + + // console.log("____________\n"); + // console.log(`Page Number : ${page}`); + // console.log(`Language : ${lang}`); + // console.log(`Genre : ${genre}`); + + // console.log("____________\n"); + + const skip_val = (page - 1) * page_size;//get the skip_val + + + // get the take_val and incorporate the case if it is last page or something greater than total number of pages + const take_val = (page <= total_number_of_pages) ? (page == total_number_of_pages ? (total_number_of_movies - (page_size * (total_number_of_pages - 1))) : 10) : 0; + + // define the prisma query + const moviesQuery = { + skip: skip_val,//set the skip value + take: take_val,//set the take value + + // if genre is not undefined add genre to where,same for lagnuage (lang) + where: { + ...(genre && { + genres: { + hasSome: [genre] + } + }), + ...(lang && { + languages: { + hasSome: [lang] + } + }) + }, + }; + + + // Search and filter the database according to the movisQuery + const movies = await prisma.embedded_movies.findMany(moviesQuery); + + // console.log("***************\n"); + // console.log(movies); + // console.log("***************\n"); + + + // console.log(`Total number of such movies : ${totalMoviesCount}`); + + // Response object + const response = { + movies: movies, + currentPage: page, + totalPages: take_val, + totalMovies: total_number_of_movies + }; + + // Send the response + res.status(200).json(response); + } + catch (error) { + // Handle errors + console.error("Error:", error); + res.status(500).json({ message: "Internal server error" }); + } +}; + + +// Enable the export feature to get it imported in the router +module.exports = { getAllMovies } \ No newline at end of file diff --git a/index.js b/index.js index 1736375..55e637a 100644 --- a/index.js +++ b/index.js @@ -3,6 +3,7 @@ const morgan = require("morgan"); const app = express(); const otpRoutes = require("./routes/otpRoutes"); +const movieRoutes=require("./routes/movie_filter"); require("dotenv").config(); @@ -15,6 +16,14 @@ app.use(morgan("tiny")); app.use("/otp", otpRoutes); +// indicate to use the route +app.use("/movie/filter",movieRoutes); +// just defining an new .get api + +app.get("/",(req,res)=>{ + res.send("Hello, how are you?"); +}) + app.listen(PORT, () => { console.log(`App listening on port ${PORT}`); }); diff --git a/package-lock.json b/package-lock.json index dbb689b..dae9cb9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,8 @@ "@prisma/client": "^5.11.0", "bcryptjs": "^2.4.3", "dotenv": "^16.4.5", - "express": "^4.18.3", + "express": "^4.19.1", + "express-async-handler": "^1.2.0", "express-validator": "^7.0.1", "mongoose": "^8.2.2", "morgan": "^1.10.0", @@ -403,9 +404,9 @@ } }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "engines": { "node": ">= 0.6" } @@ -539,16 +540,16 @@ } }, "node_modules/express": { - "version": "4.18.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", - "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.1.tgz", + "integrity": "sha512-K4w1/Bp7y8iSiVObmCrtq8Cs79XjJc/RU2YYkZQ7wpUu5ZyZ7MtPHkqoMz4pf+mgXfNvo2qft8D9OnrH2ABk9w==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -579,6 +580,11 @@ "node": ">= 0.10.0" } }, + "node_modules/express-async-handler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/express-async-handler/-/express-async-handler-1.2.0.tgz", + "integrity": "sha512-rCSVtPXRmQSW8rmik/AIb2P0op6l7r1fMW538yyvTMltCO4xQEWMmobfrIxN2V1/mVrgxB8Az3reYF6yUZw37w==" + }, "node_modules/express-validator": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-7.0.1.tgz", diff --git a/package.json b/package.json index 3d1cfb2..a1b82a1 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "@prisma/client": "^5.11.0", "bcryptjs": "^2.4.3", "dotenv": "^16.4.5", - "express": "^4.18.3", + "express": "^4.19.1", + "express-async-handler": "^1.2.0", "express-validator": "^7.0.1", "mongoose": "^8.2.2", "morgan": "^1.10.0", diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 681f505..85fc1f3 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -15,9 +15,9 @@ type EmbeddedMoviesAwards { type EmbeddedMoviesImdb { id Int - /// Multiple data types found: String: 0.2%, Float: 99.8% out of 1000 sampled entries + /// Multiple data types found: String: 0.3%, Float: 99.7% out of 1000 sampled entries rating Json - /// Multiple data types found: String: 0.2%, Int: 99.8% out of 1000 sampled entries + /// Multiple data types found: String: 0.3%, Int: 99.7% out of 1000 sampled entries votes Json } @@ -35,9 +35,9 @@ type EmbeddedMoviesTomatoes { } type EmbeddedMoviesTomatoesCritic { - meter Int + meter Int? numReviews Int - rating Float + rating Float? } type EmbeddedMoviesTomatoesViewer { @@ -54,9 +54,9 @@ type MoviesAwards { type MoviesImdb { id Int - /// Multiple data types found: String: 0.2%, Float: 99.8% out of 1000 sampled entries + /// Multiple data types found: String: 0.4%, Float: 99.6% out of 1000 sampled entries rating Json - /// Multiple data types found: String: 0.2%, Int: 99.8% out of 1000 sampled entries + /// Multiple data types found: String: 0.4%, Int: 99.6% out of 1000 sampled entries votes Json } @@ -103,20 +103,36 @@ type TheatersLocationGeo { type String } -type History { - movie_id String - timeStamp String @default("00:00:00") +model SubscriptionFeatures { + id String @id @default(auto()) @map("_id") @db.ObjectId +} + +model SubscriptionState { + id String @id @default(auto()) @map("_id") @db.ObjectId +} + +model Subscriptions { + id String @id @default(auto()) @map("_id") @db.ObjectId +} + +model User { + id String @id @default(auto()) @map("_id") @db.ObjectId + createdAt DateTime @db.Date + email String + isAdmin Boolean + name String + password String + phone String @unique + updatedAt DateTime @db.Date } model comments { - id String @id @default(auto()) @map("_id") @db.ObjectId - date DateTime @db.Date - userId String @db.ObjectId - movieId String @db.ObjectId - movie embedded_movies @relation(fields: [movieId], references: [id]) - parentId String + id String @id @default(auto()) @map("_id") @db.ObjectId + date DateTime @db.Date + email String + movie_id String @db.ObjectId + name String text String - user User @relation(fields: [userId], references: [id]) } model embedded_movies { @@ -142,70 +158,55 @@ model embedded_movies { tomatoes EmbeddedMoviesTomatoes? type String writers String[] - year Int - User User? @relation(fields: [userId], references: [id]) - userId String? @db.ObjectId - comments comments[] + /// Multiple data types found: String: 0.1%, Int: 99.9% out of 1000 sampled entries + year Json } -model User { - id String @id @default(auto()) @map("_id") @db.ObjectId - name String? - email String? - password String? - phone String @unique - isAdmin Boolean @default(false) - paymentToken String? - subscriptions SubscriptionState[] - genres String[] - languages String[] - history History[] - watchLater embedded_movies[] - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - comments comments[] +model movies { + id String @id @default(auto()) @map("_id") @db.ObjectId + awards MoviesAwards + cast String[] + countries String[] + directors String[] + fullplot String? + genres String[] + imdb MoviesImdb + languages String[] + lastupdated String + metacritic Int? + num_mflix_comments Int + plot String? + poster String? + rated String? + released DateTime? @db.Date + runtime Int? + title String + tomatoes MoviesTomatoes? + type String + writers String[] + /// Multiple data types found: String: 0.1%, Int: 99.9% out of 1000 sampled entries + year Json } -model SubscriptionState { - id String @id @default(auto()) @map("_id") @db.ObjectId - userId String @db.ObjectId - subscriptionId String @db.ObjectId - subscription Subscriptions @relation(fields: [subscriptionId], references: [id]) - status String - startDate DateTime @db.Date - endDate DateTime @db.Date - User User @relation(fields: [userId], references: [id]) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt -} - -enum SubscriptionType { - FREE - BASIC - STANDARD - PREMIUM - PLATINUM +model sessions { + id String @id @default(auto()) @map("_id") @db.ObjectId + jwt String + user_id String @unique(map: "user_id_1") } -model Subscriptions { - id String @id @default(auto()) @map("_id") @db.ObjectId - type SubscriptionType - price Float - discountPercentage Float - features SubscriptionFeatures[] - SubscriptionState SubscriptionState[] - discount Int - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt +model theaters { + id String @id @default(auto()) @map("_id") @db.ObjectId + location TheatersLocation + theaterId Int + + @@index([location.geo], map: "geo index") } -model SubscriptionFeatures { - featureId String @id @default(auto()) @map("_id") @db.ObjectId - featureName String - featureDescription String - featureValue String - Subscriptions Subscriptions? @relation(fields: [subscriptionsId], references: [id]) - subscriptionsId String? @db.ObjectId - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt +model users { + id String @id @default(auto()) @map("_id") @db.ObjectId + email String @unique(map: "email_1") + name String + password String + /// Nested objects had no data in the sample dataset to introspect a nested type. + preferences Json? } diff --git a/routes/movie_filter.js b/routes/movie_filter.js new file mode 100644 index 0000000..de7b2e2 --- /dev/null +++ b/routes/movie_filter.js @@ -0,0 +1,17 @@ +// import the express +const express=require("express"); + +// import the router +const router=express.Router(); + +// import the corresponding controller function +const {getAllMovies}=require("../controllers/movie_filter") + +// Tell the router to use getAllMovies Function if api is /movie/filter/ +router.route("/").get(getAllMovies); + +// Enabling the export features and defining the to be exported attributes +module.exports=router; + + +