• Homework: Homework 3.1: remove the lowest homework score for each student
  • Homework: Homework 3.2: Making blog accept posts
  • Homework: Homework 3.3: Making blog accept comments

Homework: Homework 3.1

To get started, please download hw3.zip or hw3.tar and unpack file to your computer. You should have included with your homework files a "students.json" file. Import this file into your local Mongo instance with this command:

Write a program in Node.js that will remove the lowest homework score for each student. Since there is a single document for each student containing an array of scores, you will need to update the scores array and remove the homework.

Hint: One way to solve this is to find the lowest homework in code and then update the scores array with the low homework removed. If you are struggling with the Node.js side of this, look at the Array.splice method, which can remove elements from a Javascript Array. Note that you should not use the delete operator, because it will delete the element without resizing the array, leaving an empty space.

To confirm you are on the right track, here are some queries to run after you process the data with the correct answer shown:

Let us count the number of students we have:

use school db.students.count() 200

Let's see what Demarcus Audette's record looks like:

db.students.find({_id:100}).pretty() { "_id" : 100, "name" : "Demarcus Audette", "scores" : [ { "type" : "exam", "score" : 47.42608580155614 }, { "type" : "quiz", "score" : 44.83416623719906 }, { "type" : "homework", "score" : 39.01726616178844 } ] }

To verify that you have completed this task correctly, provide the identify of the student with the highest average in the class with following query that uses the aggregation framework. The answer will appear in the _id field of the resulting document.

db.students.aggregate({'$unwind':'$scores'},{'$group':{'_id':'$_id', 'average':{$avg:'$scores.score'}}}, {'$sort':{'average':-1}}, {'$limit':1})

Enter just the numeric value of the _id below.

var client = require('mongodb').MongoClient,
        _ = require('underscore');
 
// parameters:
//  arry - array of student scores
// returns: array with lowest homework score dropped
var dropLowestHomeworkScore = function(arry) {
    var minVal = Number.MAX_VALUE;
    var minIdx = -1;
    var newArray = [];
 
    for (i=0; i<arry.length; i++) {
        var val = arry[i]['score'];
        var type = arry[i]['type'];
        if (type === 'homework' && val < minVal) {
            minVal = val;
            minIdx = i;
        }
    }
 
    for (i=0; i<arry.length; i++) {
        if (i !== minIdx) newArray.push(arry[i]);
    }
 
    return newArray;
};
 
var db = client.connect('mongodb://localhost:27017/school', function(err,db) {
    if (err) throw err;
 
    var students = db.collection('students');
 
    students.find({}).toArray(function(err, docs) {
        if (err) throw err;
 
        // update each doc by removing lowest score 
        _.each(docs, function(doc) {
            doc.scores = dropLowestHomeworkScore(doc.scores);
            students.update({'_id':doc._id}, doc, {}, function(err, result) {
                if (err) throw err;
            });
        });
 
        db.close()
    });
});

Homework: Homework 3.2

Making your blog accept posts

In this homework you will be enhancing the blog project to insert entries into the posts collection. After this, the blog will have the basic functionality. It will allow you to add blog posts with a title, body and tags and have it be added to the posts collection properly.

We have provided the code that creates users and allows you to login (the assignment from last week). Files for this homework and HW 3.3 should be included with your homework handout.

We have removed parts of the code that uses the Node.js driver to query MongoDB from posts.js and marked the area where you need to work for hw3.2 with "hw3.2 TODO". You should not need to touch any other code. The database call that you are going to add will insert a new post into the posts collection. Here is an example of valid blog post:

> db.posts.find().pretty()
{
"_id" : ObjectId("513d396da0ee6e58987bae74"),
"title" : "Martians to use MongoDB",
"author" : "andrew",
"body" : "Representatives from the planet Mars announced today that the planet would adopt MongoDB as a planetary standard. Head Martian Flipblip said that MongoDB was the perfect tool to store the diversity of life that exists on Mars.",
"permalink" : "martians_to_use_mongodb",
"tags" : [
"martians",
"seti",
"nosql",
"worlddomination"
],
"comments" : [ ],
"date" : ISODate("2013-03-11T01:54:53.692Z")
}

To play with the blog you can navigate to the following URLs:

http://localhost:3000/ http://localhost:3000/signup http://localhost:3000/login http://localhost:3000/newpost

#### Homework: Homework 3.3 #### Making your blog accept comments

In this homework you will add code to your blog so that it accepts comments. You will be using the same code as you downloaded for HW 3.2.

We have removed parts of the code that uses the Node.js driver to query MongoDB from posts.js and marked the area where you need to work for HW 3.3 with "hw3.3 TODO".

You should not need to touch any other code. The database call that you are going to add will add a new comment to a given post.

This assignment has fairly little code, but it's a little more subtle than the previous assignment because you are going to be manipulating an array within the Mongo document. For the sake of clarity, here is a document out of the posts collection from a working project that also has comments.

{
"_id" : ObjectId("513d396da0ee6e58987bae74"),
"author" : "andrew",
"body" : "Representatives from the planet Mars announced today that the planet would adopt MongoDB as a planetary standard. Head Martian Flipblip said that MongoDB was the perfect tool to store the diversity of life that exists on Mars.",
"comments" : [
{
"author" : "Larry Ellison",
"body" : "While I am deeply disappointed that Mars won't be standardizing on a relational database, I understand their desire to adopt a more modern technology for the red planet.",
"email" : "larry@oracle.com"
},
{
"author" : "Salvatore Sanfilippo",
"body" : "This make no sense to me. Redis would have worked fine."
}
],
"date" : ISODate("2013-03-11T01:54:53.692Z"),
"permalink" : "martians_to_use_mongodb",
"tags" : [
"martians",
"seti",
"nosql",
"worlddomination"
],
"title" : "Martians to use MongoDB"
}

Note that you add comments in this blog from the blog post detail page, which appears at

http://localhost:3000/post/post_slug

where post_slug is the permalink. For the sake of eliminating doubt, the permalink for the example blog post above is

http://localhost:3000/post/martians_to_use_mongodb

You will run hw3-3_validate.js to check your work, much like the last homework. hw3-3_validate.js will run through and check to make sure it can add blog comments, as required by this problem. This hw3-3_validate.js program will print out a 3.3 validation code that you should enter below.

POSTS.js - both 3.2 and 3.3 assignments

/* The PostsDAO must be constructed with a connected database object */
function PostsDAO(db) {
    "use strict";
 
    /* If this constructor is called without the "new" operator, "this" points
     * to the global object. Log a warning and call it correctly. */
    if (false === (this instanceof PostsDAO)) {
        console.log('Warning: PostsDAO constructor called without "new" operator');
        return new PostsDAO(db);
    }
 
    var posts = db.collection("posts");
 
    this.insertEntry = function (title, body, tags, author, callback) {
        "use strict";
        console.log("inserting blog entry" + title + body);
 
        // fix up the permalink to not include whitespace
        var permalink = title.replace( /\s/g, '_' );
        permalink = permalink.replace( /\W/g, '' );
 
        // Build a new post
        var post = {"title": title,
                "author": author,
                "body": body,
                "permalink":permalink,
                "tags": tags,
                "comments": [],
                "date": new Date()}
 
        // now insert the post
        // hw3.2 TODO
          posts.insert(post, function(err, result) {
                if (err) {
                    callback(err, null);
                } else {
                    callback(null, post.permalink);
                }
          });
    }
 
    this.getPosts = function(num, callback) {
        "use strict";
 
        posts.find().sort('date', -1).limit(num).toArray(function(err, items) {
            "use strict";
 
            if (err) return callback(err, null);
 
            console.log("Found " + items.length + " posts");
 
            callback(err, items);
        });
    }
 
    this.getPostsByTag = function(tag, num, callback) {
        "use strict";
 
        posts.find({ tags : tag }).sort('date', -1).limit(num).toArray(function(err, items) {
            "use strict";
 
            if (err) return callback(err, null);
 
            console.log("Found " + items.length + " posts");
 
            callback(err, items);
        });
    }
 
    this.getPostByPermalink = function(permalink, callback) {
        "use strict";
        posts.findOne({'permalink': permalink}, function(err, post) {
            "use strict";
 
            if (err) return callback(err, null);
 
            callback(err, post);
        });
    }
 
    this.addComment = function(permalink, name, email, body, callback) {
        "use strict";
 
        var comment = {'author': name, 'body': body}
 
        if (email != "") {
            comment['email'] = email
        }
 
        // hw3.3 TODO
          posts.findOne({permalink:permalink}, function(err, doc) {
                if (err) {
                    callback(err, null);
                } else {
                    if (doc) {
                        posts.update({_id:doc._id}, {$push: {comments:comment}}, function(err) {
                            if (err) {
                                callback(err, null);
                            } else {
                                callback(null, 1);
                            }
                        });
                    } else {
                        callback(null, 0);
                    }
                }
          });
    }
}
 
module.exports.PostsDAO = PostsDAO;

Leave a Comment

Fields with * are required.

Please enter the letters as they are shown in the image above.
Letters are not case-sensitive.