Mongo Examples part 2

// standard modules, loaded from node_modules
const path = require('path');
require("dotenv").config({ path: path.join(process.env.HOME, '.cs304env')});
const { Connection } = require('./connection');
const cs304 = require('./cs304');
const mongoUri = cs304.getMongoUri();

// ================================================================

/* Return the rating by give user of given movie.
 */

function ratingByUser(db, uid, title) {
  return db                           // identify database (in this case, a stored variable)
    .collection("ratings")            // use ratings collection
    .find({userId: uid, title: title}) // find all entries with given userId and title
    .project({rating: 1})            // only return rating field
    .toArray();                       // convert data to array to work with it in nodejs
}

/** return title and rating of all movies rated by given uid. Descending order by rating.
 */

function titleAndRatingByUser(db, uid) {
  return db                           // identify database (in this case, a stored variable)
    .collection("ratings")            // use ratings collection
    .find({userId: uid})              // find all entries with give userId
    .project({title: 1, rating: 1})   // only return title and rating fields
    .sort({rating: -1})               // sort by rating field desc (highest to lowest)
    .toArray();                       // convert data to array to work with it in nodejs
}

/** return the average rating of an array of movies. Returns null for empty array. Synchronous. 
 */

// I created this helper and re-coded.

function averageRating(movieArray) {
    let len = movieArray.length;
    if(len === 0) return null;
    let sum = 0;
    movieArray.forEach(m => sum += m.ratings);
    return sum/len;
}

/** Return average rating for given movie title. Fetches all data and computes average locally.
 */

async function getAverageRating(db, movieTitle) {
  const ratings = await db     // identify database (in this case, a stored variable)
    .collection("ratings")     // use ratings collection
    .find({title: movieTitle}) // find movie with title === "Godfather, The (1972)"
    .project({rating: 1})      // only return rating field
    .toArray();                // convert data to array to work with it in nodejs

  return averageRating(ratings);
}

/** Return average rating for given movie title. Computes average in the database server.
 */

async function getAverageRatingMongo(db, movieTitle) {
  const averageRating = await db.collection("ratings").aggregate([
    {
      $group: {
        _id: '$title',
        avgRating: { $avg: '$rating' },
      },
    },
    { $match: { _id: movieTitle } },
  ]).toArray(); // convert data to array to work with it in nodejs
  return averageRating[0].avgRating;
}

/** return the number of different (distinct) users who rated movies
 * in the movie_lens_db
 */

async function countDistinctRaters(db) {
  const result = await db   // identify db to work with (in this case, a stored variable)
    .collection("ratings")  // use ratings collection
    .distinct("userId");  // select only unique values of userId field
  return result.length; // return count of unique userIds
}

/** return the number of ratings for a particular movie title. 
 */

async function countRatingsOfMovie(db, movieTitle) {
  // find the count of ratings (NOT DISTINCT) of a certain movie in the movie_lens_db 
  const result = await db                 // identify db to work with (in this case, a stored variable)
    .collection("ratings")                // use ratings collection
    .countDocuments({title: movieTitle}); // select only values with specified title

  return result; // return count of how many times this movie has been rated
}

/** Finds the youngest person in the WMDB collection. Computes locally in Node.js 
 */

async function youngestPerson(db) {
  // find the youngest actor in the wmdb database's people collection
  const people = await db               // identify db (in this case, a stored variable)
    .collection("people")               // use people collection
    .find()                             // find all entries
    .project({name: 1, birthdate: 1})   // only return name and birthdate fields
    .toArray();                         // convert data to array to work with it in nodejs
  let youngest = {name: "", birthdate: '01-01-1800'}; // set arbitrary "oldest" birthdate

  people.forEach(person => {
    // iterate over each person in found people
    if (Date.parse(person.birthdate) > Date.parse(youngest.birthdate)) {
      youngest = person; // if person is younger than the current "youngest" birthdate, replace the value
    }
  }) 

  return youngest;
}

/** Finds the youngest person in the WMDB collection. Computes in
 * Mongo and just gets one.
 */



async function youngestPersonMongo(db) {
  // find the youngest person in the wmdb database's people collection
  const youngest = await db           // identify db (in this case, a stored variable)
    .collection("people")             // use people collection
    .find()                           // find all entries
    .project({name: 1, birthdate: 1}) // only return name and birthdate fields
    .sort({birthdate: -1})            // sort by birthdate descending (most to least recent)
    .limit(1)                         // only return the "top field" (in this case, the most recent birthdate/youngest person)
    .toArray();                       // convert data to array to work with it in nodejs
  return youngest[0]; // data is returned in an array, so return the first (and only) element
}

async function mostCredits(db) {
  // find person with most credits in wmdb
  const people = await db           // identify db (in this case, a stored variable)
    .collection("people")           // use people collection
    .find()                         // find all entries
    .project({name: 1, movies: 1})  // only return name and movies fields
    .toArray();                     // convert data to array to work with it in nodejs

  let longest = {name: "", movies_length: 0}; // select arbitrary "longest" cast length (smallest possible number -> 0)
  people.forEach(person => {                  // iterate over each found person
    if (person.movies !== undefined) {
      if (person.movies.length > longest.movies_length) { // if they're in more movies than the current stored "longest" casting list
        longest.name = person.name;                       // replace longest
        longest.movies_length = person.movies.length;
      }
    }
  }) 

  return longest;
}

async function peopleOlderThanDate(db, dateString) {
  // find all people in wmdb born after dateString 
  const people = await db             // define db (in this case, a stored variable)
    .collection("people")             // use people collection
    .find()                           // find all entries
    .project({name: 1, birthdate: 1}) // only return name and birthdate fields
    .toArray();                       // convert data to array to work with it in nodejs

  dateObj = new Date(dateString);
  let youngins = people.filter((person) => {
    return Date.parse(person.birthdate) > dateObj; // remove any people born before 2000
  });

  return youngins;
}

/** find all people in wmdb with NM >= given value
 */

function peopleMinId(db, minId) {
  return db                                       // define db (in this case, a stored variable)
    .collection("people")                         // use people collection
    .find({nm: {$gte: minId}})                    // find all people with nm >= minId
    .project({nm: 1, name: 1, birthdate: 1})      // only return nm, name and birthdate fields
    .toArray();                                   // convert data to array to work with it in nodejs
}

/** find all movies with TT <= given value
 */

function moviesMaxId(db, maxId) {
  // find all movies in wmdb with tt less than maxId
  return db                       // define db (in this case, a stored variable)
    .collection("movie")          // use movie collection
    .find({tt: {$lt: num}})      // find all entries with TT < maxId
    .project({title: 1, tt: 1})   // only return title and tt fields
    .toArray();                   // convert data to array to work with it in nodejs
}

async function insertEntry(db) {
  // insert a family member into your own collection

  // insert one into stored db value (from parameter) and family collection
  const result = await db.collection("family").insertOne( 
    {
      name: "Joseph Giandrea", 
      birthday: new Date("2003-09-26"),
      favoriteColor: "Black",
      relation: "Little Brother",
      height: 180
    }
  );
  return result.acknowledged; // return whether insertion was successful (boolean)
}

async function updateEntry(db) {
  // your baby brother has grown since you last saw him! :')
  // update the object in your own collection by increasing his height

  // update entry with name === "Joseph Giandrea" into stored db value (from parameter) and family collection
  const result = await db.collection("family").updateOne( 
    { name : "Joseph Giandrea" },
    { $set: { height : 190 } }
  );
  return result.acknowledged; // return whether updating was successful (boolean)
}

async function deleteEntry(db) {
  // your little brother is shy, and doesn't want his info out on the internet.
  // delete your brother's object from your own collection

  // delete entry with name === "Joseph Giandrea" from stored db value (from parameter) and family collection
  const result = await db.collection("family").deleteOne({ name : "Joseph Giandrea" }); 
  return result.acknowledged; // return whether deletion was successful (boolean)
}


async function main() {

  console.log('starting function check...\n');

  const movie_lens_db = await Connection.open(mongoUri, 'movie_lens_db');
  const movie1 = "Toy Story (1995)";
  const movie2 = "Godfather, The (1972)";
  const rater1 = 44;

  q1 = await ratingByUser(movie_lens_db, rater1, movie1)
  console.log(`User ${rater1} rated ${movie1}:`, q1[0]);
  q2 = await ratingByUser(movie_lens_db, rater1, movie2)
  console.log(`User ${rater1} rated ${movie2}:`, q2[0]);
  q3 = await titleAndRatingByUser(movie_lens_db, 44);
  console.log("titleAndRatingByUser:", q3.length, "movies found", q3[0]);
  q4 = await averageRating(movie_lens_db, movie2);
  console.log(`averageRating: avg rating of ${movie2}`, q4);
  q4mongo = await averageRatingMongo(movie_lens_db, movie1)
  console.log(`averageRatingMongo: avg rating of ${movie2}`, q4mongo);
  q5 = await countDistinctRaters(movie_lens_db);
  console.log("countDistinct:", q5, "distinct users found");
  q5extra = await countRatings(movie_lens_db, movie2);
  console.log("countRatings:", q5extra, `ratings for ${movie2} found`);
  await Connection.close();

  console.log("\n");

  const my_db = await Connection.open(mongoUri, 'og102');
  q10 = await insertEntry(my_db);
  console.log("insertEntry:", q10);
  q11 = await updateEntry(my_db);
  console.log("updateEntry:", q11);
  q12 = await deleteEntry(my_db);
  console.log("deleteEntry:", q12);
  console.log("deleting family collection...");
  await my_db.collection("family").drop();
  await Connection.close();

}

main().catch(console.error);