Categories
Node.js Tips

Node.js Tips — Auto-Scrolling, Delays, Hashing, and Get the Latest Mongo Document

Like any kind of apps, there are difficult issues to solve when we write Node apps.

In this article, we’ll look at some solutions to common problems when writing Node apps.

Using Q delay in Node.js

The Q promise library has a delay method that can delay the execution of code asynchronously.

For instance, we can use it by wiring:

const Q = require('q');

const asyncDelay = (ms) => {
  return Q.delay(ms);
}

asyncDelay(1000)
.then(() => {
  //...
});

We have the asyncDelay function which returns the Q.delay(ms) promise.

It returns a promise that delays the execution of something by the given number of milliseconds.

We can call it and then call then and run the code we want after asyncDelay is done in the then callback.

Also, we can pass in a 2nd argument which can be called a resolved value.

For instance, we can write:

const Q = require('q');

Q.delay(1000, "Success")
  .then((value) => {
      console.log(value);
  });

Then value would be 'Success' since that’s what we passed in as the 2nd argument of delay .

Convert an Image to a base64-Encoded Data URL

To convert an image to a base64-encoded data URL, we can use the readFileSync method to read the file’s data.

Then we pass the content into the Buffer constructor.

And then we can call toString to convert it to a base64 string.

For instance, we can write:

const fs = require('fs');

const file = 'img.jpg';
const bitmap = fs.readFileSync(file);
const dataUrl = new Buffer(bitmap).toString('base64');

We pass the file path into readFileSync .

Then we pass the returned content into the Buffer constructor.

Then we call toString with 'base64' to convert it to a base64 string.

Return the Updated Document with MongoDB findOneAndUpdate

We should set the returnOriginal property to false in the options object to return the updated document in the callback.

For instance, we can write:

db.collection('user_setting').findOneAndUpdate({
  user_id: data.userId
}, {
  $set: data
}, {
  returnOriginal: false
}, (err, res) => {
  if (err) {
    return console.log(err);
  } else {
    console.log(res);
  }
});

The first argument is the query to find the object to update.

The 2nd argument is the data to update the object with.

The 3rd is the options for updating.

We have the returnOriginal option set to false in the 3rd argument.

The last argument is the callback.

res should have the updated results.

Use jQuery Installed with NPM in Express App

To use jQuery installed with NPM in an Express app, we can serve the jQuery’s dist folder with express.static .

For instance, we can write:

const path = require('path');

app.use('/jquery', express.static(path.join(__dirname,  '/node_modules/jquery/dist/')));

Then we can use it in our HTML file by writing:

<script src="/jquery/jquery.js"></script>

Scroll Down Until We Can’t Scroll with Puppeteer

We can check if we’re at the end of the page and use the scrollBy method to scroll.

For instance, we can write:

const distance = 100;
const delay = 100;
while (document.scrollingElement.scrollTop + window.innerHeight < document.scrollingElement.scrollHeight) {
  document.scrollingElement.scrollBy(0, distance);
  await new Promise(resolve => { setTimeout(resolve, delay); });
}

We check if we’re can scroll with:

document.scrollingElement.scrollTop + window.innerHeight < document.scrollingElement.scrollHeight

When scrollTop and innerHeight is less than scrollHeight , we can scroll.

Find OS Username in Node.js

We can get the current user’s username with the os module.

We write:

require("os").userInfo().username

to get the username

In Windows 10, it returns the first name of the owner account that has been used.

There’s also the username module.

We can install it by running:

npm install username

Then we can use it by writing:

const username = require('username');

(async () => {
  console.log(await username());
})();

Hash JavaScript Objects

To hash JavaScript objects, we can use the object-hash module.

For instance, we can write:

const hash = require('object-hash');

const obj = {a: 1, b: 2};
const hashed = hash(obj);

We just call the hash function from the package to return a hashed string.

Conclusion

We can hash JavaScript objects with the object-hash module.

Also, we can get the username with os or a 3rd party module.

The Q promise library has a delay method to delay execution of functions.

We can get the updated object with findOneAndUpdate .

We can scroll until we can’t scroll with Puppeteer by checking the heights.

Categories
Node.js Tips

Node.js Tips — Socket.io, MongoDB and Nested Objects, and Express Issues

Like any kind of apps, there are difficult issues to solve when we write Node apps.

In this article, we’ll look at some solutions to common problems when writing Node apps.

Updating a Nested Array with MongoDB

We can update nested arrays with the native MongoDB driver.

To do that, we can use the update method.

We can write:

Model.update({
    "questions.answers._id": "123"
  }, {
    "$push": {
      "questions.answers.$.answeredBy": "success"
    }
  },
  (err, numAffected) => {
    // ...
  }
);

We called update with a few arguments.

The first is the query for the nested array entry to update.

The 2nd is the $push appends a new entry to the questions.answers array with the answeredBy value.

The $ sign is the positional operator, and it’s a placeholder for a single value.

Then the callback has the result after the push operation.

Express Static Relative to Parent Directory

We can use path.join to get the absolute path of the directory that we want to serve as the static folder.

For example, we can write:

const path = require('path');
const express = require('express');
const app = express();
app.use(express.static(path.join(__dirname, '../public')));

The ../ symbols move one directory level up and we get the public directory from there.

Fix ‘TypeError: Router.use() requires middleware function but got an Object’ Error in Express Apps

To fix this error, we’ve to make sure the routeing module is exported.

For instance, we can write:

users.js

const express = require('express');
const router = express.Router();

router.get('/', (req, res, next) => {
  //Do whatever...
});

module.exports = router;

We have:

module.exports = router;

to export the router .

Then we can use it in another file by writing:

const users = require('./users');

//...
app.use('/users', users);

Socket.io Error Hooking into Express.js

We can incorporate socket.io in our Express app by call the socket.io function.

For instance, we can write:

const express = require('express');
const app = express();
const server = app.listen(port);
const io = require('socket.io')(server);

We just require the socket.io module and call the required function with our server .

server is an http server instance.

Wait for Multiple Async Calls with Node.js

We can use Underscore’s or Lodash’s after method to wait for multiple async calls to be done before calling another function.

For instance, we can write:

const finished = _.after(2, baz);

foo(data, (err) => {
  //...
  finished();
});

bar(data, (err) => {
  //...
  finished();
})

const baz = () => {
  //...
}

The after method returns a finish function that we can call when the async callbacks are called.

Since we want to wait for 2 functions to finish, we pass 2 into after as the first argument.

We call finished in each callback to indicate that it’s finished.

Use Aliases with Node.js’s require Function

We can create aliases for required members by using the destructuring syntax.

For example, we can write:

const { foo: a, bar: b } = require('module');

We import a and b with require .

Then we alias a as foo and b as bar with the destructuring assignment syntax.

Then they’re accessed as foo and bar .

How to Send JavaScript Object with Socket.io

We can send JavaScript objects with socket.io in a few ways.

We can use the send method:

socket.send({ foo: 'b' });

This would convert the object automatically to JSON.

Also, we can use socket.json.send :

socket.json.send({ foo: 'b' });

And we can also use emit :

socket.emit('someEvent', { foo: 'b' });

emit emits an event with name someEvent and an object in the 2nd argument.

Get Error Status Code from HTTP GET

To get the error code for a GET request made with the http module, we can get it from the statusCode property of res .

For instance, we can write:

const https = require('https');

https.get('https://example.com/error', (res) => {
  console.log(res.statusCode);

  res.on('data', (d) => {
    process.stdout.write(d);
  });
})
.on('error', function(e) {
  console.error(e);
});

The status code is in the res.statusCode property to get the status code.

Conclusion

We can use update to update a nested array with MongoDB.

The status code of a request made with http is in the statusCode property.

We can send objects with socket.io.

Static folders should be served with absolute paths with Express.

We can use after to wait for multiple async calls to complete before calling another function.

Categories
Node.js Tips

Node.js Tips — POST Requests, Express Route Params, S3 Data, and More

Like any kind of apps, there are difficult issues to solve when we write Node apps. In this article, we’ll look at some solutions to common problems when writing Node apps.

Get the Browser Language in Express

To get the browser language in an Express app, we can use the req.headers['accept-language'] property to get the accept-language header.

Then request.acceptsLanguages method also gets the accepted language header.

For instance, we can write:

const express = require('express');
app.get('/translation', (req, res) => {
  const lang = req.acceptsLanguages('fr', 'es', 'en');
  if (lang) {
    console.log(lang);
  }
  else {
    console.log('None of [fr, es, en] is accepted');
  }
  //...
});

acceptsLanguages makes a list of languages that the app can accept.

If one of the values are in the Accepts-Language header, then it returns true ,

Otherwise, it returns false .

There’s also the accepts module that does the same thing.

To install it, we run:

npm install accepts

Then we can use it by writing:

const accepts = require('accepts');
const http = require('http');

const app = (req, res) => {
  const accept = accepts(req);
  switch (accept.type(['json', 'html'])) {
    case 'json':
      res.setHeader('Content-Type', 'application/json');
      res.write(JSON.stringify({ hello: 'world' ));
      break;
    case 'html':
      res.setHeader('Content-Type', 'text/html');
      res.write('<b>hello, world</b>');
      break;
    default:
      res.setHeader('Content-Type', 'text/plain');
      res.write('hello, world');
      break;
  }
  res.end()
}

http.createServer(app).listen(3000)

We use the accept module to check the Accept header. We can check the kind of language that it requests in the Accept header. It has the languages method to get the browser language from the Accepts-Language header.

How to Construct HTTP POST Request with Form Params

We can construct an HTTP POST request with form parameters with the querystring module.

To install it, we run:

npm i querystring

Then we can write:

const querystring = require('querystring');

axios.post(
  '/login',
  querystring.stringify({
    username: 'abcd',
    password: '12345',
  }),
  {
    headers: {
      "Content-Type": "application/x-www-form-urlencoded"
    }
  }
)
.then((response) => {
  console.log(response);
});

We called the querystring.stringify method to construct a query string with the username and password keys. Also, we set the headers with the Content-Type header set to “application/x-www-form-urlencoded” . This way, we send the query string as form data.

How to Configure Dynamic Routes with Express.js

We can configure dynamic routes with Express by allowing parameters.

For instance, we can write:

app.get('/article/:name', (req, res) => {
  res.render(req.params.name);
});

We can also restrict the allowed values of id by writing:

app.get('/article/:name(article|article2|article3)', (req, res) => {
  const name = req.params.name;
  res.render(name);
});

We restrict the name parameter to be one of article1 , article2 ,or article3 .

In both examples, we get the parameter value by using the req.params.name property.

req.params has the value of name .

Catch Express body-parser Error

We can create our own middleware to catch errors raised by body-parser .

For instance, we can write:

app.use((error, req, res, next) => {
  if (error instanceof SyntaxError) {
    sendError(res, 'error');
  } else {
    next();
  }
});

We check if a SyntaxError is raised by using error instanceof SyntaxError. If it is, then we call sendError to process the error. Otherwise, we call next to call the next middleware in the chain.

Return Hostname with Node.js

We can use the os module’s hostname method to return the hostname.

For instance, we can write:

const os = require("os");
const hostname = os.hostname();

to do that.

Listing Objects from AWS S3 in a Node App

We can get items stored in S3 with the aws-sdk package.

For instance, we can write:

const AWS = require('aws-sdk');
AWS.config.update({
  accessKeyId: 'key',
  secretAccessKey: 'secret',
  region: 'region'
});

const s3 = new AWS.S3();

const params = {
  Bucket: 'bucket',
  Delimiter: '/',
  Prefix: '/path/prefix'
}

s3.listObjects(params, (err, data) => {
  if (err){
    return console.log(err);
  }
  console.log(data);
});

We authenticate with AWS. Then we get the bucket with the Bucket property.

Delimiter is the path separator.

Prefix is the prefix for the path and bucket data.

Then we call listObjects with the path.

The callback’s data parameter has the bucket data.

Conclusion

If it’s not created when we join it, then it’ll be created. We can get data from S3. Express routes can be made dynamic with parameters. We can send form data as a query with a POST request with Axios

Categories
Node.js Tips

Node.js Tips — Express Templates and Requests, and MongoDB Queries

Like any kind of apps, there are difficult issues to solve when we write Node apps.

In this article, we’ll look at some solutions to common problems when writing Node apps.

Close the Express Server

If we need to close the Express server, we just call close on it to close it.

It’s returned from listen and it’s an HTTP server.

For instance, we can write:

const server = app.listen(3000);
server.close();

Full Text Search in MongoDB and Mongoose

We can do a search on Mongoose by creating an index on the identifier of the schema.

Indexes will speed up searches.

For instance, we can write:

const schema = new Schema({
  name: String,
});

schema.index({
  name: 'text',
});

Then we can write:

Model.find({
    $text: {
      $search: searchString
    }
  })
  .skip(20)
  .limit(10)
  .exec((err, docs) => {
    //...
  });

to do the search.

We use the $search operator to do a search on the entry.

skip skip the number of entries given in the argument.

limit limits the number of arguments.

Get the Domain that Originated the Request in Express

We can use req.get to get the hostname from the host header.

We can also use thr origin header for cross-origin requests.

To get the host header, we write:

const host = req.get('host');

And we write:

const origin = req.get('origin');

to get the origin.

Accessing Express.js Local Variables on Client-Side JavaScript

We can pass our data from our template and then parse it in there.

To do that, we write:

script(type='text/javascript').
 const localData =!{JSON.stringify(data)}

We stringified the data so that it’ll be interpolated in the template.

Add Class Conditionally with Jade/Pug

To add a class conditionally, we can write:

div.collapse(class=typeof fromEdit === "undefined" ? "edit" : "")

We put out JavaScript expression right inside the parentheses and it’ll interpolate the class name for us.

Store DB Config in a Node or Express App

We can store our config in a JSON file.

For instance, we can write:

const fs = require('fs'),
configPath = './config.json';
const parsed = JSON.parse(fs.readFileSync(configPath, 'UTF-8'));
exports.config = parsed;

We read the config with readFileSync and then call JSON.parse on the returned text string.

Exclude Some Fields from the Document with Mongoose

To exclude some fields from being returned, we convert it in the tranform method by using the delete on it to remove the property we want.

For instance, we can write:

UserSchema.set('toJSON', {
  transform(doc, ret, options) {
    delete ret.password;
    return ret;
  }
});

We call set to add a method with the transform method to transform the data.

ret has the returned result.

Then we call delete on it.

Listen on HTTP and HTTPS for a Single Express App

We can listen to HTTP and HTTPS with one Express app.

To listen to HTTP requests, we just have to read in the private and certificate files.

Then we can create a server with them.

For instance, we can write:

const express = require('express');
const https = require('https');
const http = require('http');
const fs = require('fs');
const  app = express();

const options = {
  key: fs.readFileSync('/path/key.pem'),
  cert: fs.readFileSync('/path/cert.pem'),
  ca: fs.readFileSync('/path/ca.pem')
};

http.createServer(app).listen(80);
https.createServer(options, app).listen(443);

We read in the files with readFileSync .

Then we pass the whole thing into the https.createServer method to create our server.

We still need http.createServer to listen to HTTP requests.

Get Data Passed from a form in Express

We can get the data passed from a form in Express with the body-parser package.

We use the urlencoded middleware that’s included with it.

For instance, we can write:

const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true }));

app.post('/game', (req, res) => {
  res.send(req.body);
});

Once we have ran urlencoded middleware, it’ll parse form data from POST requests.

extended means we can also parse JSON in the request body.

Then in our route, we can get the data with req.body .

Loop in Jade /Pug Template Engine

We can write a loop with Pug like a JavaScript for loop.

For instance, we write:

- for (let i = 0; i < 10; i) {
  li= array[i]
- }

Conclusion

We can have loops with Pug.

Also, we can read config from a JSON file.

Express can listen to both HTTP and HTTPS requests.

We can transform MongoDB data as we query them.

To add text search capability, we can add an index to speed up the search and use the $search operator.

Categories
Node.js Tips

Node.js Tips — Change Directory with exec, Move Files, and Nested Schemas

Like any kind of apps, there are difficult issues to solve when we write Node apps.

In this article, we’ll look at some solutions to common problems when writing Node apps.

Move File to a Different Partition or Device in Node.js

We can move file to a different partition or device by specifying the path of the destination of our write stream.

We read the file into a read stream and pipe it to a write stream.

For instance, we can write:

const fs = require('fs');
`
const rs = fs.createReadStream('source/file');
const ws = fs.createWriteStream('destination/file');
`
rs.pipe(ws);
rs.on('end', () => {
  fs.unlinkSync('source/file');
});

We call createReadStream with the source file path to read the file from a stream.

Then we call createWriteStream to create a write stream with the destination path.

We call pipe on the read stream with the write stream as the argument to pipe the read stream to the write stream.

This will copy the file from the source to the destination.

Once the copying is done, we call unlinkSync to delete the file from the source path.

We know when the copying is done when the end event is emitted.

To make our lives easier, we can use the fs.extra module’s move method.

We install it by running:

npm install fs.extra

Then we can use the move method by specifying the source and destination paths.

For instance, we can write:

const fs = require('fs.extra');
fs.move('foo.txt', 'bar.txt', (err) => {
  if (err) {
    throw err;
  }
  console.log("success");
});

We called fs.move with the source file path as the first argument.

The 2nd argument is the destination path.

The last is the callback which is run when the move operation is done.

Find Deprecation Warnings

We can find deprecation warnings by using the --trace-deprecation or --throw-deprecation options when we run our app.

For instance, we can run:

node --trace-deprecation app.js

or:

node --throw-deprecation app.js

— trace-deprecation logs a stack trace and --throw-deprecation throw an error.

We should also make sure that we include a callback function in async methods if we get something like:

(node:4346) DeprecationWarning: Calling an asynchronous function without callback is deprecated.

Calling async functions without callbacks is a big deprecated feature.

For instance, we should write:

const fs = require('fs');
//...
`
fs.writeFile('foo.txt', data, 'utf8', (error) => {
  // ...
});

The 4th argument is the callback function.

Node.js exec does not work with the “cd ” Shell Command

Each command is run in its own shell with exec, so using cd only affect the shell process that cd is run on.

If we want to change the current working directory, we’ve to set the cwd option.

For instance, we can write:

exec('git status', {
  cwd: '/repo/folder'
}, (error, stdout, stderr) => {
  if (error) {
    console.error(error);
    return;
  }
  console.log(stdout);
  console.error(stderr);
});

We switch to the /repo/folder directory by setting the cwd option in the object we passed in as the 2nd argument.

Then we can run git status on /repo/folder instead of whatever directory the app is running in.

Schema within a Schema with Mongoose

We can define a schema within a schema with Mongoose.

This way, we can store relational data with it.

For instance, we can write:

const UserSchema = new Schema({
  name: String,
  tasks: [{
    type: Schema.ObjectId,
    ref: 'Task'
  }]
});
`
const TaskSchema = new Schema({
  name: String,
  user: {
    type: Schema.ObjectId,
    ref: 'User'
  }
});

We have 2 schemas that reference each other.

We created a one to many relationships between UserSchema and TaskSchema with the tasks array.

The ref specifies the schema that we want to access.

An array indicates that it’s one to many.

Likewise, in TaskSchema , we define the user field which creates a belongs to relationship with User .

We specify an object with the 'User’ as the value of ref .

Then when we query a user, we can get all its tasks by using the populate method:

User.find({}).populate('tasks').run((err, users) => {
  //...
});

We pass in the child field we want to access, which is tasks .

Conclusion

We can define nested schemas with Mongoose to create relationships.

There are several ways to move files.

We can run node with some options to find deprecation warnings.

To change the current working directory with exec , we can set the cwd property.