{"id":21672480,"url":"https://github.com/redis-developer/basic-redisgraph-movie-demo-app-nodejs","last_synced_at":"2025-08-22T05:04:28.949Z","repository":{"id":100135782,"uuid":"342770258","full_name":"redis-developer/basic-redisgraph-movie-demo-app-nodejs","owner":"redis-developer","description":"Basic RedisGraph movie demo app written in NodeJS","archived":false,"fork":false,"pushed_at":"2023-06-30T21:37:43.000Z","size":10032,"stargazers_count":5,"open_issues_count":1,"forks_count":4,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-12T03:53:14.668Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/redis-developer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-02-27T04:29:08.000Z","updated_at":"2025-02-25T17:28:19.000Z","dependencies_parsed_at":"2025-04-12T04:04:26.872Z","dependency_job_id":null,"html_url":"https://github.com/redis-developer/basic-redisgraph-movie-demo-app-nodejs","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/redis-developer/basic-redisgraph-movie-demo-app-nodejs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis-developer%2Fbasic-redisgraph-movie-demo-app-nodejs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis-developer%2Fbasic-redisgraph-movie-demo-app-nodejs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis-developer%2Fbasic-redisgraph-movie-demo-app-nodejs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis-developer%2Fbasic-redisgraph-movie-demo-app-nodejs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/redis-developer","download_url":"https://codeload.github.com/redis-developer/basic-redisgraph-movie-demo-app-nodejs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis-developer%2Fbasic-redisgraph-movie-demo-app-nodejs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271588745,"owners_count":24785751,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-22T02:00:08.480Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-25T13:29:26.789Z","updated_at":"2025-08-22T05:04:28.940Z","avatar_url":"https://github.com/redis-developer.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Movie database app in NodeJS based on Redis Graph\n\nAn IMDB clone application based on Redis Graph and NodeJS with basic account authentication and movie recommendation functionality.\n\n\u003ca href=\"https://raw.githubusercontent.com/redis-developer/basic-redisgraph-movie-demo-app-nodejs/master/docs/a.png\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/redis-developer/basic-redisgraph-movie-demo-app-nodejs/master/docs/a.png\" width=\"48%\"\u003e\u003c/a\u003e \u003ca href=\"https://raw.githubusercontent.com/redis-developer/basic-redisgraph-movie-demo-app-nodejs/master/docs/a.png\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/redis-developer/basic-redisgraph-movie-demo-app-nodejs/master/docs/d.png\" width=\"48%\"\u003e\u003c/a\u003e\n\n## Technical Stack\n\n- Frontend - _React_\n- Backend - _Node.js_, _Redis_, _Redis Graph_\n\n## How it works\n\nThe app consumes the data provided by the Express API and presents it through some views to the end user, including:\n* Home page\n* Sign-up and Login pages\n* Movie detail page\n* Actor and Director detail page\n* User detail page\n\n### Home page\n\n![How it works](https://raw.githubusercontent.com/redis-developer/basic-redisgraph-movie-demo-app-nodejs/master/docs/a.png)\n\nThe home page shows the genres and a brief listing of movies associated with them.\n\n#### How the data is stored\n\nAdd a new genre:\n```Cypher\ncreate (g:Genre{name:\"Adventure\"})\n```\n\nAdd a movie:\n```Cypher\ncreate (m:Movie {\n    url: \"https://themoviedb.org/movie/862\",\n    id:232,\n    languages:[\"English\"],\n    title:\"Toy Story\",\n    countries:[\"USA\"],\n    budget:30000000,\n    duration:81,\n    imdbId:\"0114709\",\n    imdbRating:8.3,\n    imdbVotes:591836,\n    movieId:42,\n    plot:\"...\",\n    poster:\"https://image.tmd...\",\n    poster_image:\"https://image.tmdb.or...\",\n    released:\"1995-11-22\",\n    revenue:373554033,\n    runtime:$runtime,\n    tagline:\"A cowboy doll is profoundly t...\",\n    tmdbId:\"8844\",\n    year:\"1995\"})\n```\n\nSet genre to a movie:\n```Cypher\nMATCH (g:Genre), (m:Movie)\nWHERE g.name = \"Adventure\" AND m.title = \"Toy Story\"\nCREATE (m)-[:IN_GENRE]-\u003e(g)\n```\n\n#### How the data is accessed\n\nGet genres:\n```Cypher\nMATCH (genre:Genre) RETURN genre\n```\n\nGet moves by genre:\n```Cypher\nMATCH (movie:Movie)-[:IN_GENRE]-\u003e(genre)\nWHERE toLower(genre.name) = toLower(\"Film-Noir\") OR id(genre) = toInteger(\"Film-Noir\")\nRETURN movie\n```\n\n\n#### Code example: Get movies with genre\n```Javascript\nconst getByGenre = function (session, genreId) {\n  const query = [\n    'MATCH (movie:Movie)-[:IN_GENRE]-\u003e(genre)',\n    'WHERE toLower(genre.name) = toLower($genreId) OR id(genre) = toInteger($genreId)',\n    'RETURN movie',\n  ].join('\\n');\n\n  return session\n    .query(query, {\n      genreId,\n    })\n    .then((result) =\u003e manyMovies(result));\n};\n```\n\n### Sign-up and Login pages\n\n\u003ca href=\"https://raw.githubusercontent.com/redis-developer/basic-redisgraph-movie-demo-app-nodejs/master/docs/f.png\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/redis-developer/basic-redisgraph-movie-demo-app-nodejs/master/docs/f.png\" width=\"48%\"\u003e\u003c/a\u003e \u003ca href=\"https://raw.githubusercontent.com/redis-developer/basic-redisgraph-movie-demo-app-nodejs/master/docs/g.png\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/redis-developer/basic-redisgraph-movie-demo-app-nodejs/master/docs/g.png\" width=\"48%\"\u003e\u003c/a\u003e\n\nTo be able to rate movies a user needs to be logged in: for that a basic JWT-based authentication system is implemented, where user details are stored in the Redis Graph for persistence.\n\n#### How the data is stored\n\nStore user in the database:\n```Cypher\nCREATE (user:User {id: 32,\nusername: \"user\", password: \"hashed_password\", api_key: \"525d40da10be8ec75480\"})\nRETURN user\n```\n#### How the data is accessed\n\nFind by user name:\n```Cypher\nMATCH (user:User {username: \"user\"}) RETURN user\n```\n\n#### Code Example: Find user\n\n```Javascript\nconst me = function (session, apiKey) {\n  return session\n    .query('MATCH (user:User {api_key: $api_key}) RETURN user', {\n      api_key: apiKey,\n    })\n    .then((foundedUser) =\u003e {\n      if (!foundedUser.hasNext()) {\n        throw {message: 'invalid authorization key', status: 401};\n      }\n      while (foundedUser.hasNext()) {\n        const record = foundedUser.next();\n        return new User(record.get('user'));\n      }\n    });\n};\n```\n\n### Movie detail page\n\n![How it works](https://raw.githubusercontent.com/redis-developer/basic-redisgraph-movie-demo-app-nodejs/master/docs/d.png)\n\nOn this page a user can rate the film and view the Actors/directors who participated in the production of the film.\n\n#### How the data is stored\n\nAssociate actor with a movie:\n```Cypher\nMATCH (m:Movie) WHERE m.title=\"Jumanji\" CREATE (a:Actor :Person{\n    bio:\"Sample...\",\n    bornIn:\"Denver, Colorado, USA\",\n    imdbId:\"0000245\",\n    name:\"Robin Williams\",\n    poster:\"https://image.tmdb.org/t/p/w440_and_...\",\n    tmdbId:\"2157\",\n    url:\"https://themoviedb.org/person/2157\"})-[r:ACTED_IN_MOVIE\n    {role: \"Alan Parrish\"}]-\u003e(m)\n```\n\nAssociate director with a movie:\n```Cypher\nMATCH (m:Movie) WHERE m.title=\"Dead Presidents\" CREATE (d:Director :Person{\n    bio: \"From Wikipedia, the free e...\",\n    bornIn: \"Detroit, Michigan, USA\",\n    imdbId: \"0400436\",\n    name: \"Albert Hughes\",\n    tmdbId: \"11447\",\n    url: \"https://themoviedb.org/person/11447\"})-[r:DIRECTED]-\u003e(m)\n```\n\n#### How the data is accessed\n\nFind movie by id with genre, actors and director:\n```Cypher\nMATCH (movie:Movie {tmdbId: $movieId})\n  OPTIONAL MATCH (movie)\u003c-[my_rated:RATED]-(me:User {id: \"e1e3991f-fe81-439e-a507-aa0647bc0b88\"})\n  OPTIONAL MATCH (movie)\u003c-[r:ACTED_IN_MOVIE]-(a:Actor)\n  OPTIONAL MATCH (movie)-[:IN_GENRE]-\u003e(genre:Genre)\n  OPTIONAL MATCH (movie)\u003c-[:DIRECTED]-(d:Director)\n  WITH DISTINCT movie, my_rated, genre, d,  a, r\n  RETURN DISTINCT movie,\n  collect(DISTINCT d) AS directors,\n  collect(DISTINCT a) AS actors,\n  collect(DISTINCT genre) AS genres\n```\n\n#### Code Example: Get movie detail\n\n```Javascript\nconst getById = function (session, movieId, userId) {\n  if (!userId) throw {message: 'invalid authorization key', status: 401};\n  const query = [\n    'MATCH (movie:Movie {tmdbId: $movieId})\\n' +\n      '  OPTIONAL MATCH (movie)\u003c-[my_rated:RATED]-(me:User {id: $userId})\\n' +\n      '  OPTIONAL MATCH (movie)\u003c-[r:ACTED_IN_MOVIE]-(a:Actor)\\n' +\n      '  OPTIONAL MATCH (movie)-[:IN_GENRE]-\u003e(genre:Genre)\\n' +\n      '  OPTIONAL MATCH (movie)\u003c-[:DIRECTED]-(d:Director)\\n' +\n      '  WITH DISTINCT movie, my_rated, genre, d,  a, r\\n' +\n      '  RETURN DISTINCT movie,\\n' +\n      '  collect(DISTINCT d) AS directors,\\n' +\n      '  collect(DISTINCT a) AS actors,\\n' +\n      '  collect(DISTINCT genre) AS genres',\n  ].join(' ');\n  return session\n    .query(query, {\n      movieId: movieId.toString(),\n      userId: userId.toString(),\n    })\n    .then((result) =\u003e {\n      if (result.hasNext()) {\n        return _singleMovieWithDetails(result.next());\n      }\n      throw {message: 'movie not found', status: 404};\n    });\n};\n```\n\n\n### Actor and Director detail page\n![How it works](https://raw.githubusercontent.com/redis-developer/basic-redisgraph-movie-demo-app-nodejs/master/docs/c.png)\n\n#### How the data is accessed\n\nFind movies where actor acted in:\n```Cypher\nMATCH (actor:Actor {tmdbId: \"8537\"})-[:ACTED_IN_MOVIE]-\u003e(movie:Movie)\nRETURN DISTINCT movie,actor\n```\n\nFind movies directed by:\n```Cypher\nMATCH (director:Director {tmdbId: \"4945\"})-[:DIRECTED]-\u003e(movie:Movie)\nRETURN DISTINCT movie,director\n```\n\n#### Code Example: Get movies directed by\n\n```Javascript\nconst getByDirector = function (session, personId) {\n  const query = [\n    'MATCH (director:Director {tmdbId: $personId})-[:DIRECTED]-\u003e(movie:Movie)',\n    'RETURN DISTINCT movie,director',\n  ].join('\\n');\n\n  return session\n    .query(query, {\n      personId,\n    })\n    .then((result) =\u003e manyMovies(result));\n};\n```\n\n### User detail page\n![How it works](https://raw.githubusercontent.com/redis-developer/basic-redisgraph-movie-demo-app-nodejs/master/docs/b.png)\n\nShows the profile info and movies which were rated by user\n\n#### How the data is stored\n\nSet rating for a movie:\n```Cypher\nMATCH (u:User {id: 42}),(m:Movie {tmdbId: 231})\nMERGE (u)-[r:RATED]-\u003e(m)\nSET r.rating = \"7\"\nRETURN m\n```\n\n#### How the data is accessed\n\nGet movies and user ratings:\n```Cypher\nMATCH (:User {id: \"d6b31131-f203-4d5e-b1ff-d13ebc06934d\"})-[rated:RATED]-\u003e(movie:Movie)\nRETURN DISTINCT movie, rated.rating as my_rating\n```\n\n#### Code Example: Get rated movies for user\n\n```Javascript\nconst getRatedByUser = function (session, userId) {\n  return session\n    .query(\n      'MATCH (:User {id: $userId})-[rated:RATED]-\u003e(movie:Movie) \\\n       RETURN DISTINCT movie, rated.rating as my_rating',\n      {userId},\n    )\n    .then((result) =\u003e\n      result._results.map((r) =\u003e new Movie(r.get('movie'), r.get('my_rating'))),\n    );\n};\n```\n\n### Data types:\n\n* The data is stored in various keys and various relationships.\n    * There are 5 types of data\n        * User\n        * Director\n        * Actor\n        * Genre\n        * Movie\n\n#### Each type has its own properties\n\n   * Actor: `id, bio, born , bornIn, imdbId, name, poster, tmdbId, url`\n   * Genre: `id, name`\n   * Director: `id, born, bornIn, imdbId, name, tmdbId, url`\n   * User: `id, username, password, api_key`\n   * Movie: `id, url, languages, countries, budget, duration, imdbId, imdbRating, indbVotes, movieId, plot, poster, poster_image, released, revenue, runtime, tagline, tmdbId, year`\n\n#### And there are 4 types of relationship:\n   * User-`RATED`-\u003eMovie\n   * Director-`DIRECTED`-\u003eMovie\n   * Actor-`ACTED_IN_MOVIE`-\u003eMovie\n   * Movie-`IN_GENRE`-\u003eGenre\n\n## Hot to run it locally?\n\n### Prerequisites\n\n- Node - v13.14.0\n- NPM - v7.6.0\n\n#### Write in environment variable or Dockerfile actual connection to Redis:\n\n```\n   REDIS_ENDPOINT_URL = \"Redis server URI\"\n   REDIS_PASSWORD = \"Password to the server\"\n```\n\n### Local installation\n\nGo to main folder and then:\n\n```\n# set redis data inside\n.env\n\n# install dependencies\nnpm install\n\n# Run server\nnode app.js\n```\n\n#### Run client\n\n```sh\ncd client\nyarn install\nyarn start\n```\n\n## Try it out\n\n#### Deploy to Heroku\n\n\u003cp\u003e\n    \u003ca href=\"https://heroku.com/deploy\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://www.herokucdn.com/deploy/button.svg\" alt=\"Deploy to Heorku\" /\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n#### Deploy to Google Cloud\n\n\u003cp\u003e\n    \u003ca href=\"https://deploy.cloud.run\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://deploy.cloud.run/button.svg\" alt=\"Run on Google Cloud\" width=\"150px\"/\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredis-developer%2Fbasic-redisgraph-movie-demo-app-nodejs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fredis-developer%2Fbasic-redisgraph-movie-demo-app-nodejs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredis-developer%2Fbasic-redisgraph-movie-demo-app-nodejs/lists"}