Przeglądaj źródła

Updating Node/MongoDB Handlers to Use Default _id Index (#7792)

* Updating Node/MongoDB Handlers to Use Default _id Index

* Fixing connection bugs and moving to async/await

* Removing lean - that's a mongoose thing :)

* Moving to async/await and simplifying the update endpoint

The update endpoint used to do multiple retrievals and updates sequentially. Now it does what most of the tests do, which is just to fire off N number of parallel updates.

* Performance and accuracy improvements for mongodb related tests.

* Identified resolver-mongo to also cleanup/optimize.

* Minor cleanup

* optimized to use findOneAndUpdate

* Fixes and performance improvements for NodeJS Mongo Related tests.

* nodejs-expressjs-mongodb bugfixes
Devon 2 lat temu
rodzic
commit
9be9919eba

+ 1 - 3
frameworks/JavaScript/express/helper.js

@@ -1,8 +1,7 @@
 module.exports = {
 module.exports = {
 
 
     sanititizeTotal : (total) => {
     sanititizeTotal : (total) => {
-
-        var totalIterations;
+        let totalIterations;
         if (!total || typeof(total) != 'number') {
         if (!total || typeof(total) != 'number') {
             totalIterations = 1;
             totalIterations = 1;
         } else if(total < 501 && total > 0) {
         } else if(total < 501 && total > 0) {
@@ -16,7 +15,6 @@ module.exports = {
     },
     },
 
 
     randomizeNum : () => {
     randomizeNum : () => {
-
         return Math.floor(Math.random() * 10000) + 1
         return Math.floor(Math.random() * 10000) + 1
     }
     }
 }
 }

+ 67 - 48
frameworks/JavaScript/express/mongodb-app.js

@@ -1,35 +1,37 @@
-
 /**
 /**
  * Module dependencies.
  * Module dependencies.
  */
  */
 
 
-const cluster = require('cluster'),
-  numCPUs = require('os').cpus().length,
-  express = require('express'),
-  mongoose = require('mongoose'),
-  conn = mongoose.connect('mongodb://tfb-database/hello_world');
+const cluster = require('cluster');
+const numCPUs = require('os').cpus().length;
+const express = require('express');
+const mongoose = require('mongoose');
+const conn = mongoose.connect('mongodb://tfb-database/hello_world');
 
 
 // Middleware
 // Middleware
 const bodyParser = require('body-parser');
 const bodyParser = require('body-parser');
 
 
-const Schema = mongoose.Schema,
-  ObjectId = Schema.ObjectId;
-
+/**
+ * Note! The benchmarks say we should use "id" as a property name.
+ * However, Mongo provides a default index on "_id", so to be equivalent to the other tests, we use
+ * the same, default index provided by the database.
+ *
+ */
 const WorldSchema = new mongoose.Schema({
 const WorldSchema = new mongoose.Schema({
-  id: Number,
+  _id: Number,
   randomNumber: Number
   randomNumber: Number
 }, {
 }, {
-    collection: 'world'
-  }),
-  MWorld = mongoose.model('world', WorldSchema);
+  collection: 'world'
+});
+const MWorld = mongoose.model('world', WorldSchema);
 
 
 const FortuneSchema = new mongoose.Schema({
 const FortuneSchema = new mongoose.Schema({
-  id: Number,
+  _id: Number,
   message: String
   message: String
 }, {
 }, {
-    collection: 'fortune'
-  }),
-  MFortune = mongoose.model('fortune', FortuneSchema);
+  collection: 'fortune'
+});
+const MFortune = mongoose.model('fortune', FortuneSchema);
 
 
 if (cluster.isPrimary) {
 if (cluster.isPrimary) {
   // Fork workers.
   // Fork workers.
@@ -37,13 +39,21 @@ if (cluster.isPrimary) {
     cluster.fork();
     cluster.fork();
   }
   }
 
 
-  cluster.on('exit', (worker, code, signal) =>
-    console.log('worker ' + worker.pid + ' died'));
+  cluster.on('exit', (worker, code, signal) => console.log('worker ' + worker.pid + ' died'));
 } else {
 } else {
   const app = module.exports = express();
   const app = module.exports = express();
 
 
+  const randomTfbNumber = () => Math.floor(Math.random() * 10000) + 1;
+  const toClientWorld = (world) => {
+    if (world) {
+      world.id = world._id;
+      delete world._id;
+    }
+    return world;
+  };
+
   // Configuration
   // Configuration
-  app.use(bodyParser.urlencoded({ extended: true }));
+  app.use(bodyParser.urlencoded({extended: true}));
 
 
   // Set headers for all routes
   // Set headers for all routes
   app.use((req, res, next) => {
   app.use((req, res, next) => {
@@ -54,51 +64,60 @@ if (cluster.isPrimary) {
   app.set('view engine', 'pug');
   app.set('view engine', 'pug');
   app.set('views', __dirname + '/views');
   app.set('views', __dirname + '/views');
 
 
+  async function getRandomWorld() {
+    return toClientWorld(await MWorld.findOne({_id: randomTfbNumber()}).lean().exec());
+  }
+
   // Routes
   // Routes
   app.get('/mongooseq', async (req, res) => {
   app.get('/mongooseq', async (req, res) => {
-    const queries = Math.min(parseInt(req.query.queries) || 1, 500),
-      results = [];
+    const queryCount = Math.min(parseInt(req.query.queries) || 1, 500);
+    const promises = [];
 
 
-    for (let i = 1; i <= queries; i++) {
-      results.push(await MWorld.findOne({ id: (Math.floor(Math.random() * 10000) + 1) }));
+    for (let i = 1; i <= queryCount; i++) {
+      promises.push(getRandomWorld());
     }
     }
 
 
-    res.send(results);
+    res.send(await Promise.all(promises));
   });
   });
 
 
   app.get('/mongoose', async (req, res) => {
   app.get('/mongoose', async (req, res) => {
-    let results = await MWorld.findOne({ id: (Math.floor(Math.random() * 10000) + 1) });
+    const result = await MWorld.findOne({_id: randomTfbNumber()}).lean().exec();
 
 
-    res.send(results);
+    res.send(toClientWorld(result));
   });
   });
 
 
-  app.get('/mongoose-fortune', (req, res) => {
-    MFortune.find({}, (err, fortunes) => {
-      const newFortune = { id: 0, message: "Additional fortune added at request time." };
-      fortunes.push(newFortune);
-      fortunes.sort((a, b) => (a.message < b.message) ? -1 : 1);
+  app.get('/mongoose-fortune', async (req, res) => {
+    const fortunes = (await MFortune.find({}).lean().exec()).map(toClientWorld);
+    const newFortune = {id: 0, message: "Additional fortune added at request time."};
+    fortunes.push(newFortune);
+    fortunes.sort((a, b) => (a.message < b.message) ? -1 : 1);
 
 
-      res.render('fortunes/index', { fortunes: fortunes });
-    });
+    res.render('fortunes/index', {fortunes});
   });
   });
 
 
+  async function getUpdateRandomWorld() {
+    // it would be nice to use findOneAndUpdate here, but for some reason the test fails with it.
+    const world = await MWorld.findOne({_id: randomTfbNumber()}).lean().exec();
+    world.randomNumber = randomTfbNumber();
+    await MWorld.updateOne({
+      _id: world._id
+    }, {
+      $set: {
+        randomNumber: world.randomNumber
+      }
+    }).exec();
+    return toClientWorld(world);
+  }
+
   app.get('/mongoose-update', async (req, res) => {
   app.get('/mongoose-update', async (req, res) => {
-    const results = [],
-      queries = Math.min(parseInt(req.query.queries) || 1, 500);
-
-    for (let i = 1; i <= queries; i++) {
-      const world = await MWorld.findOne({ id: (Math.floor(Math.random() * 10000) + 1) });
-      world.randomNumber = ~~(Math.random() * 10000) + 1;
-      await MWorld.update({
-        id: world.id
-      }, {
-          randomNumber: world.randomNumber
-        });
-
-      results.push(world);
+    const queryCount = Math.min(parseInt(req.query.queries, 10) || 1, 500);
+    const promises = [];
+
+    for (let i = 1; i <= queryCount; i++) {
+      promises.push(getUpdateRandomWorld());
     }
     }
 
 
-    res.send(results);
+    res.send(await Promise.all(promises));
   });
   });
 
 
   app.listen(8080);
   app.listen(8080);

+ 70 - 56
frameworks/JavaScript/express/resolver-mongo.js

@@ -1,83 +1,97 @@
 const mongoose = require('mongoose');
 const mongoose = require('mongoose');
 const helper = require('./helper');
 const helper = require('./helper');
 
 
-const Schema = mongoose.Schema,
-  ObjectId = Schema.ObjectId;
-
 const WorldSchema = new mongoose.Schema({
 const WorldSchema = new mongoose.Schema({
-  id: Number,
+  _id: Number,
   randomNumber: Number
   randomNumber: Number
 }, {
 }, {
-    collection: 'world'
-  }),
-  World = mongoose.model('world', WorldSchema);
+  collection: 'world'
+});
+const World = mongoose.model('world', WorldSchema);
 
 
 const FortuneSchema = new mongoose.Schema({
 const FortuneSchema = new mongoose.Schema({
-  id: Number,
+  _id: Number,
   message: String
   message: String
 }, {
 }, {
-    collection: 'fortune'
-  }),
-  Fortune = mongoose.model('fortune', FortuneSchema);
+  collection: 'fortune'
+});
+const Fortune = mongoose.model('fortune', FortuneSchema);
 
 
-// Methods
+const toClientWorld = (world) => {
+  if (world) {
+    world.id = world._id;
+    delete world._id;
+  }
+  return world;
+};
 
 
-async function arrayOfRandomWorlds(totalWorldToReturn) {
+async function getRandomWorld() {
+  return toClientWorld(await World.findOne({_id: helper.randomizeNum()}).lean().exec());
+}
 
 
-    var totalIterations = helper.sanititizeTotal(totalWorldToReturn);
-    var arr = [];
+// Methods
 
 
-    return new Promise(async (resolve, reject) => {
-        for(var i = 0; i < totalIterations; i++) {
-            arr.push(await World.findOne({ id: helper.randomizeNum() }));
-        }
-        if(arr.length == totalIterations) {
-            resolve(arr);
-        }
-    });
-};
+async function arrayOfRandomWorlds(totalWorldsToReturn) {
+  const totalIterations = helper.sanititizeTotal(totalWorldsToReturn);
+  const promises = [];
 
 
-async function updateRandomWorlds(totalToUpdate) {
+  for (let i = 1; i <= totalIterations; i++) {
+    promises.push(getRandomWorld());
+  }
 
 
-    const totalIterations = helper.sanititizeTotal(totalToUpdate);
-    var arr = [];
+  return await Promise.all(promises);
+}
 
 
-    return new Promise(async (resolve, reject) => {
-        for(var i = 0; i < totalIterations; i++) {
+async function getAndUpdateRandomWorld() {
+  // it would be nice to use findOneAndUpdate here, but for some reason the test fails with it.
+  const world = await World.findOne({_id: helper.randomizeNum()}).lean().exec();
+  world.randomNumber = helper.randomizeNum();
+  await World.updateOne({
+    _id: world._id
+  }, {
+    $set: {
+      randomNumber: world.randomNumber
+    }
+  }).exec();
+  return toClientWorld(world);
+}
 
 
-            arr.push(await World.findOneAndUpdate({ id: helper.randomizeNum() }, { randomNumber: helper.randomizeNum() }));
-        }
-        if(arr.length == totalIterations) {
-            resolve(arr);
-        }
-    });
-};
+async function updateRandomWorlds(totalToUpdate) {
+  const totalIterations = helper.sanititizeTotal(totalToUpdate);
+  const promises = [];
 
 
-const sayHello = () => {
+  for (let i = 1; i <= totalIterations; i++) {
+    promises.push(getAndUpdateRandomWorld());
+  }
 
 
-    var helloWorld = new Object;
-    helloWorld.message = "Hello, World!";
+  return await Promise.all(promises);
+}
 
 
-    return JSON.stringify(helloWorld);
+const sayHello = () => {
+  return JSON.stringify({
+    message: "Hello, World!"
+  });
 };
 };
 
 
 module.exports = {
 module.exports = {
-    Query: {
-        helloWorld: () => sayHello(),
-        getAllWorlds: async() => await World.find({}),
-        singleDatabaseQuery: async() => await World.findOne({ id: helper.randomizeNum() }),
-        multipleDatabaseQueries: async(parent, args) => await arrayOfRandomWorlds(args.total),
-        getWorldById: async(parent, args) => await World.findById(args.id),
-        getAllFortunes: async() => await Fortune.find({}),
-        getRandomAndUpdate: async(parent, args) => await updateRandomWorlds(args.total)
+  Query: {
+    helloWorld: () => sayHello(),
+    getAllWorlds: async () => toClientWorld(await World.find({}).lean().exec()),
+    singleDatabaseQuery: async () => toClientWorld(await World.findOne({_id: helper.randomizeNum()}).lean().exec()),
+    multipleDatabaseQueries: async (parent, args) => await arrayOfRandomWorlds(args.total),
+    getWorldById: async (parent, args) => toClientWorld(await World.findById(args.id).lean().exec()),
+    getAllFortunes: async () => toClientWorld(await Fortune.find({}).lean().exec()),
+    getRandomAndUpdate: async (parent, args) => await updateRandomWorlds(args.total)
+  },
+  Mutation: {
+    createWorld: async (parent, args) => {
+      const randInt = helper.randomizeNum();
+      return await World.create({_id: null, randomNumber: randInt});
     },
     },
-    Mutation: {
-        createWorld: async(parent, args) => {
-            let randInt = Math.floor(Math.random() * 1000) + 1;
-            return await World.create({ id: null, randomNumber: randInt });
-        },
-        updateWorld: async(parent, args) => {
-            return await World.update({id: args.id, randomNumber: args.randomNumber});
-        }
+    updateWorld: async (parent, args) => {
+      return World.updateOne({_id: args.id}, {
+        randomNumber: args.randomNumber
+      }).exec();
     }
     }
+  }
 }
 }

+ 91 - 63
frameworks/JavaScript/nodejs/handlers/mongodb-raw.js

@@ -1,93 +1,121 @@
 const h = require('../helper');
 const h = require('../helper');
-const async = require('async');
 const MongoClient = require('mongodb').MongoClient;
 const MongoClient = require('mongodb').MongoClient;
-const collections = {
-  World: null,
-  Fortune: null
-};
+let collectionsMaybe = null, connecting = false, connectionCallbacks = [];
 
 
 const mongoUrl = 'mongodb://tfb-database:27017';
 const mongoUrl = 'mongodb://tfb-database:27017';
 const dbName = 'hello_world';
 const dbName = 'hello_world';
 
 
-MongoClient.connect(mongoUrl, (err, database) => {
-  // do nothing if there is err connecting to db
-
-  collections.World = database.db(dbName).collection('world');
-  collections.Fortune = database.db(dbName).collection('fortune');
-});
+/**
+ * Note! The benchmarks say we should use "id" as a property name.
+ * However, Mongo provides a default index on "_id", so to be equivalent to the other tests, we use
+ * the same, default index provided by the database.
+ *
+ */
+
+const getCollections = async () => {
+  // mongoose creates a queue of requests during connection, so we don't have to wait.
+  // however, with the raw driver we need to connect first, or sometimes the test will fail randomly
+  if (collectionsMaybe) {
+    return collectionsMaybe;
+  }
+  if (connecting) {
+    const promise = new Promise((resolve) => {
+      connectionCallbacks.push(resolve);
+    });
+    return await promise;
+  }
+  connecting = true;
+  const client = await MongoClient.connect(mongoUrl);
+  collectionsMaybe = {
+    World: null,
+    Fortune: null
+  };
+  collectionsMaybe.World = client.db(dbName).collection('world');
+  collectionsMaybe.Fortune = client.db(dbName).collection('fortune');
+
+  // resolve pending requests in buffer
+  for (const callback of connectionCallbacks) {
+    callback(collectionsMaybe);
+  }
 
 
+  return collectionsMaybe;
+}
 
 
-const mongodbRandomWorld = (callback) => {
-  collections.World.findOne({
-    id: h.randomTfbNumber()
-  }, (err, world) => {
-    world._id = undefined; // remove _id from query response
-    callback(err, world);
-  });
+const toClientWorld = (world) => {
+  if (world) {
+    world.id = world._id;
+    delete world._id;
+  }
+  return world;
 };
 };
 
 
-const mongodbGetAllFortunes = (callback) => {
-  collections.Fortune.find().toArray((err, fortunes) => {
-    callback(err, fortunes);
-  })
+
+const mongodbRandomWorld = async () => {
+  const collections = await getCollections();
+  return toClientWorld(await collections.World.findOne({
+    _id: h.randomTfbNumber()
+  }));
 };
 };
 
 
-const mongodbDriverUpdateQuery = (callback) => {
-  collections.World.findOne({ id: h.randomTfbNumber() }, (err, world) => {
-    world.randomNumber = h.randomTfbNumber();
-    collections.World.update({ id: world.id }, world, (err, updated) => {
-      callback(err, { id: world.id, randomNumber: world.randomNumber });
-    });
-  });
+const mongodbGetAllFortunes = async () => {
+  const collections = await getCollections();
+  return (await collections.Fortune.find({}).toArray()).map(toClientWorld);
 };
 };
 
 
+async function getUpdateRandomWorld() {
+  const collections = await getCollections();
+  const world = await collections.World.findOne({
+    _id: h.randomTfbNumber()
+  });
+  world.randomNumber = h.randomTfbNumber();
+  await collections.World.updateOne({
+    _id: world._id
+  }, {
+    $set: {
+      randomNumber: world.randomNumber
+    }
+  })
+  return toClientWorld(world);
+}
 
 
 module.exports = {
 module.exports = {
 
 
-  SingleQuery: (req, res) => {
-    mongodbRandomWorld((err, result) => {
-      if (err) { return process.exit(1) }
-
-      h.addTfbHeaders(res, 'json');
-      res.end(JSON.stringify(result));
-    });
+  SingleQuery: async (req, res) => {
+    const result = await mongodbRandomWorld();
+    h.addTfbHeaders(res, 'json');
+    res.end(JSON.stringify(result));
   },
   },
 
 
-  MultipleQueries: (queries, req, res) => {
-    const queryFunctions = h.fillArray(mongodbRandomWorld, queries);
-
-    async.parallel(queryFunctions, (err, results) => {
-      if (err) { return process.exit(1) }
+  MultipleQueries: async (queryCount, req, res) => {
+    const queryFunctions = [];
+    for (let i = 0; i < queryCount; i++) {
+      queryFunctions.push(mongodbRandomWorld());
+    }
+    const results = await Promise.all(queryFunctions);
 
 
-      h.addTfbHeaders(res, 'json');
-      res.end(JSON.stringify(results));
-    });
+    h.addTfbHeaders(res, 'json');
+    res.end(JSON.stringify(results));
   },
   },
 
 
-  Fortunes: (req, res) => {
-    mongodbGetAllFortunes((err, fortunes) => {
-      if (err) { return process.exit(1) }
-
-      fortunes.push(h.additionalFortune());
-      fortunes.sort(function (a, b) {
-        return a.message.localeCompare(b.message);
-      });
-      h.addTfbHeaders(res, 'html');
-      res.end(h.fortunesTemplate({
-        fortunes: fortunes
-      }));
+  Fortunes: async (req, res) => {
+    const fortunes = await mongodbGetAllFortunes();
+    fortunes.push(h.additionalFortune());
+    fortunes.sort(function (a, b) {
+      return a.message.localeCompare(b.message);
     });
     });
+    h.addTfbHeaders(res, 'html');
+    res.end(h.fortunesTemplate({fortunes}));
   },
   },
 
 
-  Updates: (queries, req, res) => {
-    const queryFunctions = h.fillArray(mongodbDriverUpdateQuery, queries);
+  Updates: async (queryCount, req, res) => {
+    const promises = [];
 
 
-    async.parallel(queryFunctions, (err, results) => {
-      if (err) { return process.exit(1) }
+    for (let i = 1; i <= queryCount; i++) {
+      promises.push(getUpdateRandomWorld());
+    }
 
 
-      h.addTfbHeaders(res, 'json');
-      res.end(JSON.stringify(results));
-    });
+    h.addTfbHeaders(res, 'json');
+    res.end(JSON.stringify(await Promise.all(promises)));
   }
   }
 
 
 };
 };

+ 74 - 71
frameworks/JavaScript/nodejs/handlers/mongoose.js

@@ -1,103 +1,106 @@
 const h = require('../helper');
 const h = require('../helper');
-const async = require('async');
 const Mongoose = require('mongoose');
 const Mongoose = require('mongoose');
+// These .set() calls can be removed when mongoose is upgraded to v5.
+Mongoose.set('useNewUrlParser', true);
+Mongoose.set('useFindAndModify', false);
+Mongoose.set('useUnifiedTopology', true);
 const connection = Mongoose.createConnection('mongodb://tfb-database/hello_world');
 const connection = Mongoose.createConnection('mongodb://tfb-database/hello_world');
 
 
+/**
+ * Note! The benchmarks say we should use "id" as a property name.
+ * However, Mongo provides a default index on "_id", so to be equivalent to the other tests, we use
+ * the same, default index provided by the database.
+ *
+ */
+
 // Mongoose Setup
 // Mongoose Setup
 const WorldSchema = new Mongoose.Schema({
 const WorldSchema = new Mongoose.Schema({
-  id: Number,
+  _id: Number,
   randomNumber: Number
   randomNumber: Number
 }, {
 }, {
-    collection: 'world'
-  });
+  collection: 'world'
+});
 const FortuneSchema = new Mongoose.Schema({
 const FortuneSchema = new Mongoose.Schema({
-  id: Number,
+  _id: Number,
   message: String
   message: String
 }, {
 }, {
-    collection: 'fortune'
-  });
+  collection: 'fortune'
+});
 
 
 const Worlds = connection.model('World', WorldSchema);
 const Worlds = connection.model('World', WorldSchema);
 const Fortunes = connection.model('Fortune', FortuneSchema);
 const Fortunes = connection.model('Fortune', FortuneSchema);
 
 
-const mongooseRandomWorld = (callback) => {
-  Worlds.findOne({
-    id: h.randomTfbNumber()
-  }).exec(callback);
+const toClientWorld = (world) => {
+  if (world) {
+    world.id = world._id;
+    delete world._id;
+  }
+  return world;
 };
 };
 
 
-const mongooseGetAllFortunes = (callback) => {
-  Fortunes.find({})
-    .exec(callback);
+const mongooseRandomWorld = async () => {
+  return toClientWorld(await Worlds.findOne({
+    _id: h.randomTfbNumber()
+  }).lean().exec());
 };
 };
 
 
-module.exports = {
+const mongooseGetAllFortunes = async () => {
+  return (await Fortunes.find({})
+      .lean().exec()).map(toClientWorld);
+};
 
 
-  SingleQuery: (req, res) => {
-    mongooseRandomWorld((err, result) => {
-      if (err) { return process.exit(1); }
+async function getUpdateRandomWorld() {
+  // it would be nice to use findOneAndUpdate here, but for some reason the test fails with it.
+  const world = await Worlds.findOne({_id: h.randomTfbNumber()}).lean().exec();
+  world.randomNumber = h.randomTfbNumber();
+  await Worlds.updateOne({
+    _id: world._id
+  }, {
+    $set: {
+      randomNumber: world.randomNumber
+    }
+  }).exec();
+  return toClientWorld(world);
+}
 
 
-      h.addTfbHeaders(res, 'json');
-      res.end(JSON.stringify(result));
-    })
-  },
+module.exports = {
 
 
-  MultipleQueries: (queries, req, res) => {
-    const queryFunctions = h.fillArray(mongooseRandomWorld, queries);
+  SingleQuery: async (req, res) => {
+    const result = await mongooseRandomWorld();
+    h.addTfbHeaders(res, 'json');
+    res.end(JSON.stringify(result));
+  },
 
 
-    async.parallel(queryFunctions, (err, results) => {
-      if (err) { return process.exit(1); }
+  MultipleQueries: async (queryCount, req, res) => {
+    const queryFunctions = [];
+    for (let i = 0; i < queryCount; i++) {
+      queryFunctions.push(mongooseRandomWorld());
+    }
+    const results = await Promise.all(queryFunctions);
 
 
-      h.addTfbHeaders(res, 'json');
-      res.end(JSON.stringify(results));
-    });
+    h.addTfbHeaders(res, 'json');
+    res.end(JSON.stringify(results));
   },
   },
 
 
-  Fortunes: (req, res) => {
-    mongooseGetAllFortunes((err, fortunes) => {
-      if (err) { return process.exit(1); }
-
-      fortunes.push(h.additionalFortune());
-      fortunes.sort((a, b) => {
-        return a.message.localeCompare(b.message);
-      });
-      h.addTfbHeaders(res, 'html');
-      res.end(h.fortunesTemplate({
-        fortunes: fortunes
-      }))
+  Fortunes: async (req, res) => {
+    const fortunes = await mongooseGetAllFortunes();
+    fortunes.push(h.additionalFortune());
+    fortunes.sort((a, b) => {
+      return a.message.localeCompare(b.message);
     });
     });
+    h.addTfbHeaders(res, 'html');
+    res.end(h.fortunesTemplate({fortunes}));
   },
   },
 
 
-  Updates: (queries, req, res) => {
-    const selectFunctions = h.fillArray(mongooseRandomWorld, queries);
-
-    async.parallel(selectFunctions, (err, worlds) => {
-      if (err) { return process.exit(1); }
-
-      const updateFunctions = [];
-
-      for (let i = 0; i < queries; i++) {
-        ((i) => {
-          updateFunctions.push((callback) => {
-            worlds[i].randomNumber = h.randomTfbNumber();
-            Worlds.update({
-              id: worlds[i].id
-            }, {
-                randomNumber: worlds[i].randomNumber
-              }, callback);
-          });
-        })(i);
-      }
-
-      async.parallel(updateFunctions, (err, results) => {
-        if (err) { return process.exit(1); }
-
-        h.addTfbHeaders(res, 'json');
-        // results does not have updated document information
-        // if no err: all updates were successful
-        res.end(JSON.stringify(worlds));
-      });
-    });
+  Updates: async (queryCount, req, res) => {
+    const promises = [];
+
+    for (let i = 1; i <= queryCount; i++) {
+      promises.push(getUpdateRandomWorld());
+    }
+
+    h.addTfbHeaders(res, 'json');
+    res.end(JSON.stringify(await Promise.all(promises)));
   }
   }
 
 
 };
 };

+ 6 - 6
frameworks/JavaScript/nodejs/helper.js

@@ -2,6 +2,12 @@ const Handlebars = require('handlebars');
 
 
 const GREETING = "Hello, World!";
 const GREETING = "Hello, World!";
 
 
+const headerTypes = {
+  plain: 'text/plain',
+  json:  'application/json',
+  html:  'text/html; charset=UTF-8'
+};
+
 const self = module.exports = {
 const self = module.exports = {
 
 
   additionalFortune: () => ({
   additionalFortune: () => ({
@@ -41,12 +47,6 @@ const self = module.exports = {
   },
   },
 
 
   addTfbHeaders: (res, headerType) => {
   addTfbHeaders: (res, headerType) => {
-    const headerTypes = {
-      plain: 'text/plain',
-      json:  'application/json',
-      html:  'text/html; charset=UTF-8'
-    };
-    
     res.setHeader('Server', 'Node');
     res.setHeader('Server', 'Node');
     res.setHeader('Content-Type', headerTypes[headerType]);
     res.setHeader('Content-Type', headerTypes[headerType]);
 },
 },

+ 1 - 1
frameworks/JavaScript/nodejs/routing.js

@@ -1,4 +1,4 @@
-// Intialized database connections, one for each db config
+// Initialized database connections, one for each db config
 // * Mongoose is a popular Node/MongoDB driver
 // * Mongoose is a popular Node/MongoDB driver
 // * Sequelize is a popular Node/SQL driver
 // * Sequelize is a popular Node/SQL driver