Commit 518de02d authored by Kristian Freeman's avatar Kristian Freeman

Answer key - node exercises

parent 63358bc2
...@@ -3,25 +3,16 @@ const mongoose = require("mongoose"); ...@@ -3,25 +3,16 @@ const mongoose = require("mongoose");
const assert = require("assert"); const assert = require("assert");
const seed = require("./utils/seed"); const seed = require("./utils/seed");
// Import the User model from './user'. Make sure to check const User = require("./user");
// the file for anything that needs to be done!
// A number of functions have been defined, which need
// functionality filled in before they can be used. Each
// function includes an assertion to confirm that the
// query you provide correctly passes the requirements.
async function getAllUsers() { async function getAllUsers() {
// Set the variable users to the result of finding const users = await User.find();
// _all_ the users.
console.log(`Found ${users.length} users`); console.log(`Found ${users.length} users`);
assert.equal(users.length, 101, "Expected to find 101 users!"); assert.equal(users.length, 101, "Expected to find 101 users!");
} }
async function getVerifiedUsers() { async function getVerifiedUsers() {
// Set the variable users to the result of finding const users = await User.find({ verified: true });
// all users where verified is true.
console.log(`Found ${users.length} verified users`); console.log(`Found ${users.length} verified users`);
users.forEach(user => users.forEach(user =>
...@@ -34,12 +25,7 @@ async function getVerifiedUsers() { ...@@ -34,12 +25,7 @@ async function getVerifiedUsers() {
} }
async function getAdultUsers() { async function getAdultUsers() {
// Set the variable users to the result of finding const users = await User.find({ age: { $gt: 21 } });
// all users where age is greater than 21.
// Queries of this format are done by setting the field as a key,
// and then using the $gt operator, like so:
//
// Event.find({ user_count: { $gt: 100 } });
console.log(`Found ${users.length} users over 21`); console.log(`Found ${users.length} users over 21`);
users.forEach(user => users.forEach(user =>
...@@ -52,12 +38,7 @@ async function getAdultUsers() { ...@@ -52,12 +38,7 @@ async function getAdultUsers() {
} }
async function getUsersWithLongLastNames() { async function getUsersWithLongLastNames() {
// More complicated lookups can be done by passing the $where condition const users = await User.find({ $where: "this.name.last.length > 9" });
// into .find. Set the value of users to the result of any user where
// name.last.length is greater than 9. For instance, if we were looking
// for an event name, we would do something like...
//
// Event.find({ $where: 'this.name.length > 20' })
console.log(`Found ${users.length} users with long last names`); console.log(`Found ${users.length} users with long last names`);
users.forEach(user => users.forEach(user =>
...@@ -70,9 +51,9 @@ async function getUsersWithLongLastNames() { ...@@ -70,9 +51,9 @@ async function getUsersWithLongLastNames() {
} }
async function getKristian() { async function getKristian() {
// Find one user in the database by calling .findOne. Lookup the user const user = await User.findOne({
// by passing a name object, with first set to "Kristian" and last set to name: { first: "Kristian", last: "Freeman" }
// "Freeman". Set the value of this function call to user. });
console.log(`Found ${user.name.first}!`); console.log(`Found ${user.name.first}!`);
assert.equal( assert.equal(
...@@ -88,23 +69,16 @@ async function getKristian() { ...@@ -88,23 +69,16 @@ async function getKristian() {
assert.equal(user.age, 25, "The user's age in getKristian is incorrect"); assert.equal(user.age, 25, "The user's age in getKristian is incorrect");
} }
// Once you've filled in all the queries, you should call them in the
// initialize function below.
async function initialize() { async function initialize() {
await connect(); await connect();
await mongoose.connection.dropDatabase(); await mongoose.connection.dropDatabase();
await seed(); await seed();
// Call the defined functions, ensuring that each is prefixed await getAllUsers();
// with await: await getVerifiedUsers();
// - getAllUsers await getAdultUsers();
// - getVerifiedUsers await getUsersWithLongLastNames();
// - getAdultUsers await getKristian();
// - getUsersWithLongLastNames
// - getKristian
// End your code here!
console.log("OK :)"); console.log("OK :)");
await mongoose.connection.close(); await mongoose.connection.close();
......
const mongoose = require("mongoose"); const mongoose = require("mongoose");
// Define userSchema by calling the function const userSchema = mongoose.Schema({
// mongoose.Schema, passing in an object where: name: { first: String, last: String },
// - name is an object, with first and last as Strings description: String,
// - description is a string location: String,
// - location is a string age: Number,
// - age is a number verified: Boolean,
// - verified is a boolean created_at: { type: Date, default: Date.now() },
// - created_at is an object, with a type of Date and updated_at: { type: Date, default: Date.now() }
// default set to Date.now });
// - updated_at is an object, with a type of Date and
// default set to Date.now const User = mongoose.model("User", userSchema);
// module.exports = User;
// Define User to the value of the function mongoose.model,
// passing in the string "User" and userSchema.
//
// Export User using module.exports.
...@@ -2,91 +2,21 @@ const mongoose = require("mongoose"); ...@@ -2,91 +2,21 @@ const mongoose = require("mongoose");
const connect = require("./utils/connection"); const connect = require("./utils/connection");
const { User } = require("./models/User"); const { User } = require("./models/User");
/* const createUser = async () => {
* In this exercise, we'll define a few mongoose schemas, connect();
* and utilize them to: mongoose.connection.dropDatabase();
* 1. Connect to mongodb await User.create({
* 2. Create a user with todos name: "Kristian",
* 3. Find the user in the database after it's been created username: "signalnerve",
* 4. Log the user out todos: [
* 5. And close the mongodb connection { name: "Finish this exercise" },
* { name: "Get lunch" },
* To begin, go to ./models/User, and begin defining your { name: "Learn Express, MongoDB, and all the JS in the world" }
* User schema! You'll be directed back here when it's time to write ]
* the createUser function. });
* const user = await User.find();
* Now that we're back in index.js, it's time to finish this exercise console.log(user);
* and actually use the models and schemas we've defined. mongoose.connection.close();
* };
* Create a new function createUser - this is going to be an
* _asynchronous function_, so we should prefix the function with the
* async keyword:
*
* async function whateverFunc() {
* }
*
* This async function will allow us to use the powerful async/await
* functionality in Node - instead of relying heavily on Promise behavior
* (.then, .catch, etc), which leads to a lot of nested code and confusing
* readability issues, async and await will make our code a lot cleaner
* and easier to follow.
*
* The createUser function is going to do a couple things (and you could
* argue that some of them should be separate functions, but for now,
* we'll go with it):
*
* 1. Call the connect function, which has been imported from utils/connection.
* This function connects to the mongodb instance, and sets up a global
* connection inside of mongoose that we'll re-use throughout the function.
*
* 2. Drops the database, by calling mongoose.connection.dropDatabase. This is
* optional - if you don't add this line, there will be multiple instances
* of our user model inside of the database. If you do call this function,
* 2. Calls User.create, passing in an object with the data we want to provide
* to our user. The data we pass in will look something like this:
*
* {
* name: "Kristian",
* username: "signalnerve",
* todos: [
* { name: "Finish this exercise" },
* { name: "Get lunch" },
* { name: "Learn Express, MongoDB, and all the JS in the world" }
* ]
* }
*
* Pass in a name and username of your choice, and define at least 2 or 3
* todos of your own as well.
*
* Finally, prefix this function with "await". This means that the function will
* wait for this function to finish executing before continuing with the
* rest of the code. The format will look something like this:
*
* await myFunc();
*
* 3. Our code will now wait for the user to be created before continuing. Once
* the user is created, we should look the user back up, to confirm that
* it's actually been persisted in the database. To do this, call User.find,
* setting it to the variable user. Because this is an asynchronous operation,
* we need to prefix the User.find call with await!
*
* 4. With our user retrieved from the DB, let's simply console.log it out to see
* what the data looks like.
*
* 5. Finally, let's close the mongoose connection by calling
* mongoose.connection.close. If we were to kill this node process, or type
* Control-C, it's likely that the connection would close on its own. But we
* should be safe and ensure that once we're done working with MongoDB, we close
* the connection explicitly and not leave any hanging connections to the DB that
* we don't keep track of.
*
* 6. As a bonus trick, let's comment out all of the code surrounding dropping the
* database and creating a user, just leaving the User.find code. When we run
* this exercise again, we should make sure that the user is being persisted to
* the MongoDB database. If it does... congrats! We've created a database :)
*
*/
async function createUser() {}
createUser(); createUser();
/* const mongoose = require("mongoose");
* Similarly to the User file, we'll define another
* schema for todos in this file. const todoSchema = new mongoose.Schema({
* name: String,
* One interesting aspect here is that todos will be notes: String,
* _nested_ underneath users: a user _has_ many todos, created_at: { type: Date, default: Date.now() },
* and we won't really be creating a Todo model without updated_at: { type: Date, default: Date.now() },
* it being attached to a user. Because of this, we'll completed_at: { type: Date }
* just define a todoSchema, and export it to be used inside of });
* the User model.
* module.exports = { todoSchema };
* Let's start by importing mongoose, similarly to how we did
* it in the User model file.
*
* Now define todoSchema, which is the value of calling
* new mongoose.Schema, passing in a single argument, the fields
* for our schema:
*
* - name is a string
* - notes is a string
* - created_at is an object, with a type of Date and default of
* Date.now
* - updated_at is an object, with a type of Date and default of
* Date.now
* - completed_at is an object, with a type of Date (and no default)
*
* With this schema defined, we're going to skip defining a Todo
* model itself! Again, the reason for this is that todos will live
* inside of the User model, and so we care exclusively about using
* the todoSchema inside of our userSchema.
*
* The one caveat here is that in a future design of this application,
* we may want to use the Todo model directly, for instance, if we
* need to lookup a Todo independent of a User. We'll examine that later:
* for now, simply export the todoSchema, using the same syntax that we
* used for exporting User in the previous file.
*
* Once you've done that, go back to models/User to finish the implementation
* of our models and schemas.
*
*/
/* const mongoose = require("mongoose");
* A mongoose schema defines common functionality for const { todoSchema } = require("./Todo");
* querying and creating models in mongodb. Let's define a User
* schema! const userSchema = new mongoose.Schema({
* name: String,
* To begin, import the mongoose package, naming the variable username: String,
* "mongoose". created_at: { type: Date, default: Date.now() },
* updated_at: { type: Date, default: Date.now() },
* We can now define our first schema. call new mongoose.Schema, todos: [todoSchema]
* passing a single object argument with our user fields. Fields });
* are defined as key value pairs, like so:
* const User = mongoose.model("User", userSchema);
* new mongoose.Schema({
* name: String module.exports = { User };
* // ...more fields
* })
*
* The user fields we should define are:
* - name, which is a String
* - username, which is a String
* - created_at, which is an object with two key value pairs:
* type, which is Date, and default, which is Date.now
* - updated_at, which is an object with two key value pairs:
* type, which is Date, and default, which is Date.now
*
* Once you've defined the User schema, we should actually
* instantiate the mongoose model. Do this by calling the function
* mongoose.model, passing in two arguments: the string "User"
* (the model name), and the userSchema. Set the value of this
* model to User.
*
* Before moving on to our next model, let's export User from this
* file. Set module.exports to an object, passing in a single key, User.
* The format will look like this:
*
* module.exports = { Thing }
*
* Now move on to models/Todo.js - we'll come back to this file soon!
*
* Once you've finished models/Todo.js, we need to use the todoSchema
* inside of our userSchema. Import todoSchema from ./Todo, using
* the named import format. Given a schema and source file Event, this
* would look something like:
*
* const { eventSchema } = require('./Event')
*
* Now we want to use the todosSchema inside of our userSchema. Add a new
* field todos, setting the value to an array with a single value, todoSchema:
*
* const userSchema = new mongoose.Schema({
* // ...
* events: [eventSchema],
* // ...
* });
*
* With this work completed, let's go back to index.js and finish the exercise.
*
*/
...@@ -3,34 +3,11 @@ const express = require("express"); ...@@ -3,34 +3,11 @@ const express = require("express");
const app = express(); const app = express();
const posts = require("./lib/posts"); const posts = require("./lib/posts");
/* app.set("view engine", "pug")
* First, let's set "pug" as our app's view engine. To do this,
* call app.set, passing in two arguments: "view engine", as the key
* to set, and a value of the string "pug". Note we _aren't_ importing
* the "pug" package: express does this for us.
*/
/* app.get("/", (req, res) => {
* Next, we'll define a route, GET "/", that renders the actual template. res.render("index", { posts })
* If you don't remember how to define a route, look at some of our previous })
* exercises. Set the path to "/", and in the callback function, call
* res.render, passing the name of the template we want to render as the
* first argument (we want to render "index"), and the data we want to
* pass into the template as the second argument. In our case, let's pass in
* an object with a key and value of "posts". We've already imported a "posts"
* array above, so we're going to use it in the template here.
*/
/* app.listen(PORT, () => console.log(`Listening on ${PORT}`))
* Let's actually ensure that the application is set up, too. Call
* app.listen, passing in PORT as the first argument, and a callback
* function as the second: it can simply console.log something like
* "Listening on ${PORT}", or whatever you'd like the application to say when
* it's ready for requests.
*/
/*
* To ensure that everything is working, go to localhost:PORT (PORT defaults to 8080,
* unless you change it or pass a PORT environment variable), and look for the template
* being rendered. If you see a couple blog post-looking text tags, congrats! You did it!
*/
html
link(
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous"
)
//- First, let's create the "body" for our page.
//- At the same level of indentation as this comment,
//- add the tag "body". Remember, in Pug, there's no
//- <body> or anything like that: just "body" on its own.
//- Indentation is important, too! Add the tag right
//- below this comment.
//- Next, add a "div" element underneath this comment
//- (keeping the same level of indentation). You can
//- pass classes to the element by adding .yourClass
//- after the tag, like div.myClass. You can even append
//- multiple, by doing div.myClass.myClassTwo.
//- Try adding the classes "container" and "mt-5".
//- At this indentation level, add an h1 tag with the
//- text "My cool blog" (or whatever you prefer). To do this,
//- write "h1" and then your text, like this:
//- h1 Testing one two
//- Underneath this comment, add a div element with class
//- "py-4".
//- Now we should actually pass some data in here. Go to `index.js`
//- and make sure that you're passing "posts" into the res.render
//- call.
//-
//- To loop through an array, like posts, we'll use the "each" syntax.
//- each x in y
//- h2= x.name
//- h2= x.date
//-
//- Do something similar to the above example, but render out the following
//- (assuming the variable "post"):
//-
//- 1. An h2 with value post.postTitle
//- 2. A p with post.postContent
//- 3. A p with the text "Posted on <postDate>". Try using interpolation
//- for postDate - if I had a name variable, I'd do something like:
//-
//- p My name is #{myVar}
//-
//- Fill in all three of these fields, at this indentation level.
//- You may need to restart your server for the changes to appear!
\ No newline at end of file
//- To start, copy and paste the contents of layout.pug into this html
//- file. You can delete this comment, too! link(
\ No newline at end of file rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous"
)
body
div.container.mt-5
h1 My cool blog
div.py-4
each post in posts
h2 #{post.postTitle}
p #{post.postContent}
p Posted on #{post.postDate}
/* const num = require("./lib/handlers/num");
* Import two files using the `require` function: const version = require("./lib/utils/version");
* 1. num, which is located at 'lib/handlers/num'
* 2. version, which is located at 'lib/utils/version'
*
* You'll need to make changes to these files, so check them as well!
*
* Next, define a function "init" which does two things:
* 1. console.log calling the numHandler function on num with the argument 99
* 2. Return the response of the function loadVersion defined on version
*
* Make sure to check `lib/handlers/num` and `lib/utils/version` for the rest of the exercise!
*
*/
// Start your work here!
const init = () => {
console.log(num.numHandler(99));
return version.loadVersion();
};
// No changes are needed below this line // No changes are needed below this line
console.log(init()); console.log(init());
const assert = require("assert"); const assert = require("assert");
assert.equal(num.numHandler(99), 99, "The num handler file should be required as the variable 'num': calling num.numHandler(99) should return 99. Check your imports and exports."); assert.equal(
assert.equal(version.loadVersion(), "1.0.0", "The version file should be required as the variable 'version': calling version.loadVersion() should return '1.0.0'. Check your imports and exports."); num.numHandler(99),
99,
"The num handler file should be required as the variable 'num': calling num.numHandler(99) should return 99. Check your imports and exports."
);
assert.equal(
version.loadVersion(),
"1.0.0",
"The version file should be required as the variable 'version': calling version.loadVersion() should return '1.0.0'. Check your imports and exports."
);
/* const numHandler = number => number;
* Define the function numHandler, which takes an argument number module.exports = { numHandler };
* and simply returns it.
*
* Also define the export for this file: module.exports should equal
* an object with the key and value numHandler (there is an ES6 shorthand for this!)
*/
/* const data = require("../configuration/data");
* Using `require`, load the file `configuration/data`, which is one directory const loadVersion = () => data.version;
* _up_ from the current directory (use ".."). Set this to data. module.exports = { loadVersion };
*
* Define the function loadVersion, which returns data.version.
*
* Also define the export for this file: module.exports should equal
* an object with the key and value loadVersion (there is an ES6 shorthand for this!)
*/
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment