Thursday, February 18, 2021

JavaScript Features That Are Introduced In ES2021

  1. String.prototype.replaceAll
    A new string method to replace all occurrences items.
    const catPhrase = 'A cat sat on the cat mat';
    const dogPhrase = catPhrase.replaceAll('cat', 'dog');
    console.log(dogPhrase); // A dog sat on the dog mat
    

  2. Logical Assignment Operators

    - Or Or Equals

    Or Or Equals provides a nice shorthand for us to provide an alternative value if the initial value is empty. 

    In the first example below, as a is truthy, a remains equal to “hello”.
    let a = “hello”;
    a ||= 10;
    console.log(a); // hello
    
    In the second example, found below, as b is falsey the value is then set to “world”.
    let b = “”;
    b ||= “world”;
    console.log(b); // world
    - And And Equals
    And And Equals provides a nice shorthand for us to override a value if a previous value was defined.

    In the first example below, as a is truthy, a is then set to “hello”.
    let a = true;
    a &&= “hello”;
    console.log(a); // hello
    In the second example below, as b is falsey, b remained equal fo false.
    let b = false;
    b &&= “world”;
    console.log(b); false

  3. Numeric Separators
    Numeric Separators introduces the separators for numeric literals with the intent to make them easier to read. Before ES2021 we would write our million value as follows:
    const billion = 1000000000
    With Numeric Separators we can make the number much easier to read by introducing underscores.
    const billion = 1_000_000_000

  4. Private Methods and Fields
    ES2021 finally fixes this omission by introducing private methods and private fields. To indicate a method or field is private you simply need to use a hash (#) before the name.
    class ClassWithPrivateField {
     #privateField
    }
    
    class ClassWithPrivateMethod {
     #privateMethod() {
     return 'hello world'
     }
    }
    
    class ClassWithPrivateStaticField {
     static #PRIVATE_STATIC_FIELD
    }
    Class was introduced on ES6, you may refer to below article:
    https://scalaoncloud.blogspot.com/2016/12/javascript-evolution-esmascript-6.html

Wednesday, February 17, 2021

Nodejs Data Caching with Redis Part 3: Performance Testing

This testing is running on 12GB RAM Window PC. NodeJS, MongoDB and Redis are installed on standalone PC.

The test is querying 10,000 documents.

It takes 1005ms response time query from MongoDB Server.


40% faster where 594ms response time from Redis Cache.



Here is all about Redis Cache.

Are you interested in live scoreboard build with Redis Sorted Set and Socket Programming? Feel free to let me know, probably my next sharing.

Tuesday, February 16, 2021

Nodejs Data Caching with Redis Part 2: Ultimate Way

I have shown an example of a direct approach on how to use Redis on NodeJS in Part 1. The disadvantage of the direct approach is redundant code where you have to initial Redis Server and to check whether there is a cache whenever you use it.

In this part 2, I am going to centralise the intitial Redis Server and add new method in mongoose:

.cache() = Cache value into redis memory database.

clearCache() = Delete value from redis memory database.

You can download the code at https://github.com/htsiah/node-redis-mongodb

The Redis Code store in utils/useCacheUtil.js and the sample code at controllers/TeacherController.js

Wednesday, February 10, 2021

Nodejs Data Caching with Redis Part 1: Caching in Action

You have to install Redis, Another Redis Desktop Manager and NPM Redis for this example.

Install Redis on Linux

Install Redis on Window

Install free version Another Redis Desktop Manager to view the cache data. 

Install NPM Redis
npm install redis

This is how you connect redis in NodeJS:
const redis = require('redis')
const redisURL = 'redis://127.0.0.1:6379'
const client = redis.createClient(redisURL)

For basic value, you can use set and get method. The first parameter is the search key and second parameter value stored.

// Store 'hi' as search key, and value is 'there'.
client.set('hi','there');

// Output: there
client.get('hi', ( err, val) => { console.log(val) } )

Redis support hset where you can have 2 search keys. Generally, I think it is practical to use hset for mongodb where the search keys are collection name and search query.



You may refer example on CRUD in StudentController:

Create - http://localhost/api/student
- When there is new document, delete collection in the cache.
redisClient.del(StudentModel.collection.collectionName)


Read - http://localhost/api/student/6028c376ddf84b2bd0a6b6b3
- If there is cache data, return cache data.
      const cacheStudent = await redisClient.hget(
        StudentModel.collection.collectionName
        JSON.stringify(query.getQuery())
      )

      if (cacheStudent) {
        // Remember convert to javascript object
        console.log('Get from cache.')
        return res.json(JSON.parse(cacheStudent)); 
      }  
- If not, find the data in mongodb, store the data to redis and return the data.
      const student = await query.exec();

      redisClient.hset(
        StudentModel.collection.collectionName
        JSON.stringify(query.getQuery()), 
        JSON.stringify(student.toObject({ getters: false }))
      )

Update - http://localhost/api/student/6028c376ddf84b2bd0a6b6b3
- Same as create, delete the collection.

Delete - http://localhost/api/student/6028c376ddf84b2bd0a6b6b3
- Same as create, delete the collection.

The above is an example using collection as key. The different requirement may use different key.

Sunday, February 7, 2021

Transactions With Mongoose & NodeJs, Express

Local Machine Implementation:

Transactions only work on replicate sets. So, the first step is to convert your standalone MongoDb instance to single replicate set. 

  1. Shutdown MongoDB Server.
  2. Add below entry to mongod.cfg
    replication:
      replSetName: "rs0"
  3. Start MongoDb Server.
  4. Initiate the replica set from within the mongo shell using command "rs.initiate()".

After converting to replicate set, we can work on the NodeJs code.


Docker Implementation:

1.Create a dockerfile: mongo.dockerfile
FROM mongo
RUN echo "rs.initiate();" > /docker-entrypoint-initdb.d/replica-init.js
CMD ["--replSet", "rs0"]

2. Installation:
2.1 Build the image
docker build -t custom-replica-mongo . -f mongo.dockerfile`
2.2 start the instance
docker run custom-replica-mongo

3. Create with docker-compose
version: '3'
services:
  mongo:
    image: custom-replica-mongo
    build:
      context: .
      dockerfile: mongo.dockerfile
    ports:
     - 27017:27017


Create a model: 

const StudentModel= mongoose.model('StudentModel', new mongoose.Schema({

  year: { type: Number },

  standard: { type: Number },

}));

Example of saving a document using transaction:

const createStudent = async (req, res, next) => {

    const { year, standard } = req.body;


    const session = await StudentModel.startSession();

    session.startTransaction();


    const newStudent = new StudentModel({

      id: uuidv4(),

      year: year,

      standard: standard,

    })

  

    try {

      const opts = { session };

      await newStudent.save(opts);


      // commit the changes if everything was successful

      await session.commitTransaction();

      session.endSession();

    } catch (err) {

      // If an error occurred, abort the whole transaction and

      // undo any changes that might have happened

      await session.abortTransaction();

      session.endSession();


      const error = new Error(' Creating document failed.');

      return next(error);

    }

  

    res.status(201).json(newStudent);

};

For full example of transaction in MVC, you can refer below repository.

The example included updating, delete in transaction.

References:
https://docs.mongodb.com/manual/tutorial/convert-standalone-to-replica-set/