Search This Blog

Wednesday, March 21, 2018

working with nexted array in mongo


We will create a sample collection in mongo

    db.nx.insert(
    {
    "user":"john",
    "cart_item":[
            {
             "product":"product1",
             "unit_price":5,
             "qty":2,
             "total":0
            },
            {
             "product":"product2",
             "unit_price":6,
             "qty":3,
             "total":0
            },
            {
             "product":"product3",
             "unit_price":4,
             "qty":6,
             "total":0
            }
        ]
    }
    )

lets see inserted document

    db.nx.find().pretty()

    output:
        {
            "_id" : ObjectId("5ab290094d5d23c1ed27c8a2"),
            "user" : "john",
            "cart_item" : [
                {
                    "product" : "product1",
                    "unit_price" : 5,
                    "qty" : 2,
                    "total" : 0
                },
                {
                    "product" : "product2",
                    "unit_price" : 6,
                    "qty" : 3,
                    "total" : 0
                },
                {
                    "product" : "product3",
                    "unit_price" : 4,
                    "qty" : 6,
                    "total" : 0
                }
            ]
        }


We want to update cart_item object array total using unit_price & qty.

Here is one way to do so


db.nx.find({ "_id" : ObjectId("5ab290094d5d23c1ed27c8a2")}).forEach(function(item) { 
  var new_cart_item=[];
  for(var i=0;i < item.cart_item.length;i++){
     item.cart_item[i].total = item.cart_item[i].unit_price * item.cart_item[i].qty;
     new_cart_item.push(item.cart_item[i])
  }

  db.nx.update({ "_id" : ObjectId("5ab290094d5d23c1ed27c8a2")}, {
    $set: { "cart_item": new_cart_item }
  })
})

now we will see modified collection

db.nx.find().pretty()
output:
{
    "_id" : ObjectId("5ab290094d5d23c1ed27c8a2"),
    "user" : "john",
    "cart_item" : [
        {
            "product" : "product1",
            "unit_price" : 5,
            "qty" : 2,
            "total" : 10
        },
        {
            "product" : "product2",
            "unit_price" : 6,
            "qty" : 3,
            "total" : 18
        },
        {
            "product" : "product3",
            "unit_price" : 4,
            "qty" : 6,
            "total" : 24
        }
    ]
}

Sunday, March 18, 2018

Javascript - cloning An object array



consider following code snippet.We will check different ways to clone an object array and check if cloning is deep or shallow.
var game_popularity = [
    { game: "fruit ninja", popularity: 78 },
    { game: "road runner", popularity: 20 },
    { game: "maze runner", popularity: 40 },
    { game: "ludo", popularity: 75 },
    { game: "temple runner", popularity: 86 }
];
console.log("sorted original array before clonning");
game_popularity.sort((a, b) => a.popularity < b.popularity);
console.log(game_popularity);


console.log("clone using object assign");
const cl2 = game_popularity.map(a => Object.assign({}, a));
cl2[1].game = "clash of titan";
cl2.push({ game: "logan", popularity: 57 });
console.log(cl2);


//adding new array element doesnt reflect in original array
console.log("clone using concat");
var ph = []
var cl = ph.concat(game_popularity);

//copied by reference ?
cl[0].game = "rise of civilization";

game_popularity[0].game = 'ping me';
cl.push({ game: "angry bird", popularity: 67 });
console.log(cl);

console.log("clone using ellipses");
var cl3 = [...game_popularity];
cl3.push({ game: "blue whale", popularity: 67 });
cl3[2].game = "harry potter";
console.log(cl3);

console.log("clone using json.parse");
var cl4 = JSON.parse(JSON.stringify(game_popularity));
cl4.push({ game: "home alone", popularity: 87 });
cl4[3].game ="lockhead martin";
console.log(cl4);

console.log("clone using Object.create");
var cl5 = Array.from(Object.create(game_popularity));
cl5.push({ game: "fish ville", popularity: 87 });
cl5[3].game ="veto power";
console.log(cl5);


console.log("clone using lodash-->cloneDeep");
var cl6 = _.cloneDeep(game_popularity);
cl6.push({ game: "crop ville", popularity: 67 });
cl6[3].game ="shooter";
console.log(cl6);

console.log("clone using lodash-->clone");
var cl7 = _.clone(game_popularity);
cl7.push({ game: "ice age", popularity: 61 });
cl7[3].game ="car theft";
console.log(cl7);

//array function
console.log("sorted original array after clonning");
game_popularity.sort((a, b) => a.popularity < b.popularity);
console.log(game_popularity);


console.log("Object.assign deep clone object array");
console.log("json.parse deep clone object array");
console.log("concat does not deep clone object array");
console.log("ellipses does not deep clone object array");
console.log("Object.create does not deep clone object array");
console.log("lodash-->cloneDeep deep clone object array");
console.log("lodash-->clone shallow copy object array");


output:


sorted original array before clonning
[ { game: 'temple runner', popularity: 86 },
  { game: 'fruit ninja', popularity: 78 },
  { game: 'ludo', popularity: 75 },
  { game: 'maze runner', popularity: 40 },
  { game: 'road runner', popularity: 20 } ]
clone using object assign
[ { game: 'temple runner', popularity: 86 },
  { game: 'clash of titan', popularity: 78 },
  { game: 'ludo', popularity: 75 },
  { game: 'maze runner', popularity: 40 },
  { game: 'road runner', popularity: 20 },
  { game: 'logan', popularity: 57 } ]
clone using concat
[ { game: 'ping me', popularity: 86 },
  { game: 'fruit ninja', popularity: 78 },
  { game: 'ludo', popularity: 75 },
  { game: 'maze runner', popularity: 40 },
  { game: 'road runner', popularity: 20 },
  { game: 'angry bird', popularity: 67 } ]
clone using ellipses
[ { game: 'ping me', popularity: 86 },
  { game: 'fruit ninja', popularity: 78 },
  { game: 'harry potter', popularity: 75 },
  { game: 'maze runner', popularity: 40 },
  { game: 'road runner', popularity: 20 },
  { game: 'blue whale', popularity: 67 } ]
clone using json.parse
[ { game: 'ping me', popularity: 86 },
  { game: 'fruit ninja', popularity: 78 },
  { game: 'harry potter', popularity: 75 },
  { game: 'lockhead martin', popularity: 40 },
  { game: 'road runner', popularity: 20 },
  { game: 'home alone', popularity: 87 } ]
clone using Object.create
[ { game: 'ping me', popularity: 86 },
  { game: 'fruit ninja', popularity: 78 },
  { game: 'harry potter', popularity: 75 },
  { game: 'veto power', popularity: 40 },
  { game: 'road runner', popularity: 20 },
  { game: 'fish ville', popularity: 87 } ]
clone using lodash-->cloneDeep
[ { game: 'ping me', popularity: 86 },
  { game: 'fruit ninja', popularity: 78 },
  { game: 'harry potter', popularity: 75 },
  { game: 'shooter', popularity: 40 },
  { game: 'road runner', popularity: 20 },
  { game: 'crop ville', popularity: 67 } ]
clone using lodash-->clone
[ { game: 'ping me', popularity: 86 },
  { game: 'fruit ninja', popularity: 78 },
  { game: 'harry potter', popularity: 75 },
  { game: 'car theft', popularity: 40 },
  { game: 'road runner', popularity: 20 },
  { game: 'ice age', popularity: 61 } ]
sorted original array after clonning
[ { game: 'ping me', popularity: 86 },
  { game: 'fruit ninja', popularity: 78 },
  { game: 'harry potter', popularity: 75 },
  { game: 'car theft', popularity: 40 },
  { game: 'road runner', popularity: 20 } ]
Object.assign deep clone object array
json.parse deep clone object array
concat does not deep clone object array
ellipses does not deep clone object array
Object.create does not deep clone object array
lodash-->cloneDeep deep clone object array



Conclusion:

json.parse,lodash-->cloneDeep are doing deep copy of object array.

Object.assign does not do deep copy  please refer below link

http://msdotnetbuddy.blogspot.com/2018/09/objectassign-in-javascipt.html
 

Mongo Agreegation I

 Here we will explore group by clause in mongo.

Inserting Sample Data:
    Query:
        db.studentinfo.insertMany([
            {"name":"sagar","class":10,"marathi":80,"english":75,"history":68,"geography":78,"hindi":67,"math":76,"science1":67,"science2":70,"region":"rural","school":"A"},
            {"name":"sangram","class":10,"marathi":81,"english":72,"history":60,"geography":72,"hindi":62,"math":70,"science1":68,"science2":72,"region":"rural","school":"A"},
            {"name":"sachin","class":10,"marathi":69,"english":62,"history":80,"geography":82,"hindi":72,"math":70,"science1":78,"science2":70,"region":"urban","school":"B"},
            {"name":"swapnil","class":10,"marathi":60,"english":60,"history":80,"geography":72,"hindi":82,"math":60,"science1":68,"science2":80,"region":"urban","school":"C" },
            {"name":"rock","class":10,"marathi":81,"english":72,"history":70,"geography":72,"hindi":62,"math":74,"science1":68,"science2":69,"region":"rural","school":"A"},
            {"name":"mary","class":10,"marathi":67,"english":71,"history":80,"geography":82,"hindi":72,"math":69,"science1":78,"science2":84,"region":"urban","school":"B"},
            ]);
    output:
        {
            "acknowledged" : true,
            "insertedIds" : [
                ObjectId("5aa4b8fae7232cc5677a7738"),
                ObjectId("5aa4b8fae7232cc5677a7739"),
                ObjectId("5aa4b8fae7232cc5677a773a"),
                ObjectId("5aa4b8fae7232cc5677a773b")
            ]
        }

Sum:
    db.studentinfo.aggregate([
             { $match: { class: 10 } },
             { $group: { _id: "$region", total: { $sum: "$marathi" } } },
           ])

Group by Multiple Columns:

    db.studentinfo.aggregate([
                 { $match: { class: 10 } },
                     { $group: { _id: {"region": "$region","class": "$class"}, total: { $sum: "$marathi" } } },
                   ])

    db.studentinfo.aggregate([
                 { $match: { class: 10 } },
                     { $group: { _id: {"region": "$region","school": "$school"}, marathi: { $sum: "$marathi" }, hindi: { $sum: "$hindi" } , english: { $sum: "$english" }} },
                   ])


    db.studentinfo.aggregate([
                 { $match: { class: 10,region:"rural" } },
                     { $group: { _id: {"region": "$region","school": "$school"}, marathi: { $sum: "$marathi" }, hindi: { $sum: "$hindi" } , english: { $sum: "$english" }} },
                   ])

Projection:

    db.studentinfo.aggregate([
                 { $match: { class: 10,region:"rural" } },
                     { $group: { _id: {"region": "$region","school": "$school"}, marathi: { $sum: "$marathi" }, hindi: { $sum: "$hindi" } , english: { $sum: "$english" }} },
                 {$project : {region : '$_id.region', school : '$_id.school', marathi : '$marathi',hindi : '$hindi',english : '$english', _id : 0}}
                   ])
    db.studentinfo.aggregate([
                 { $match: { class: 10} },
                     { $group: { _id: {"region": "$region","school": "$school"}, marathi: { $sum: "$marathi" }, hindi: { $sum: "$hindi" } , english: { $sum: "$english" }} },
                 {$project : {region : '$_id.region', school : '$_id.school', marathi : '$marathi',hindi : '$hindi',english : '$english', _id : 0}}
                   ])
Sorting:

    db.studentinfo.aggregate([
                 { $match: { class: 10} },
                     { $group: { _id: {"region": "$region","school": "$school"}, marathi: { $sum: "$marathi" }, hindi: { $sum: "$hindi" } , english: { $sum: "$english" }} },
                 {$project : {region : '$_id.region', school : '$_id.school', marathi : '$marathi',hindi : '$hindi',english : '$english', _id : 0}},
                 {$sort:{"region":1,"school":1}}
                   ])

    db.studentinfo.aggregate([
                 { $match: { class: 10} },
                     { $group: { _id: {"region": "$region","school": "$school"}, marathi: { $avg: "$marathi" }, hindi: { $avg: "$hindi" } , english: { $avg: "$english" }} },
                 {$project : {region : '$_id.region', school : '$_id.school', marathi : '$marathi',hindi : '$hindi',english : '$english', _id : 0}},
                 {$sort:{"region":1,"school":1}}
                   ])

Making Sum of two column in mongo

Query:
    db.studentinfo.aggregate([
            { "$project" : {
                    'name':'$name',
                    'socialscience' : { '$add' : [ '$history','$geography' ] },
                    'science' : { '$add' : [ '$science1','$science2' ] },
                    'language' : { '$add' : [ '$marathi', '$hindi','$english' ] },
                }
            }
              ])
Output:
    { "_id" : ObjectId("5aa4bbe212899b0fde851291"), "name" : "sagar", "socialscience" : 146, "science" : 137, "language" : 222 }
    { "_id" : ObjectId("5aa4bbe212899b0fde851292"), "name" : "sangram", "socialscience" : 132, "science" : 140, "language" : 215 }
    { "_id" : ObjectId("5aa4bbe212899b0fde851293"), "name" : "sachin", "socialscience" : 162, "science" : 148, "language" : 203 }
    { "_id" : ObjectId("5aa4bbe212899b0fde851294"), "name" : "swapnil", "socialscience" : 152, "science" : 148, "language" : 202 }
    { "_id" : ObjectId("5aa4bbe212899b0fde851295"), "name" : "rock", "socialscience" : 142, "science" : 137, "language" : 215 }
    { "_id" : ObjectId("5aa4bbe212899b0fde851296"), "name" : "mary", "socialscience" : 162, "science" : 162, "language" : 210 }

Query:
    db.studentinfo.aggregate([
            { "$project" : {
                    'name':'$name',
                    'class':'$class',
                    'region':'$region',
                                'school':'school',
                    'total_socialscience' : { '$add' : [ '$history','$geography' ] },
                    'total_science' : { '$add' : [ '$science1','$science2' ] },
                    'total_language' : { '$add' : [ '$marathi', '$hindi','$english' ] },

                                'avg_science':{ $divide: [ { '$add' : [ '$science1','$science2' ] }, 2 ] },
                                'avg_socialscience':{ $divide: [ { '$add' : [ '$history','$geography' ] }, 2 ] },
                                'avg_language':{ $divide: [ { '$add' : [ '$marathi', '$hindi','$english' ] }, 3 ] },
                }
            }
              ])

Output:
        { "_id" : ObjectId("5aa4bbe212899b0fde851291"), "name" : "sagar", "class" : 10, "region" : "rural", "school" : "school", "total_socialscience" : 146, "total_science" : 137,
        "total_language" : 222, "avg_science" : 68.5, "avg_socialscience" : 73, "avg_language" : 74 }
        { "_id" : ObjectId("5aa4bbe212899b0fde851292"), "name" : "sangram", "class" : 10, "region" : "rural", "school" : "school", "total_socialscience" : 132, "total_science" : 140,
        "total_language" : 215, "avg_science" : 70, "avg_socialscience" : 66, "avg_language" : 71.66666666666667 }
        { "_id" : ObjectId("5aa4bbe212899b0fde851293"), "name" : "sachin", "class" : 10, "region" : "urban", "school" : "school", "total_socialscience" : 162, "total_science" : 148,
        "total_language" : 203, "avg_science" : 74, "avg_socialscience" : 81, "avg_language" : 67.66666666666667 }
        { "_id" : ObjectId("5aa4bbe212899b0fde851294"), "name" : "swapnil", "class" : 10, "region" : "urban", "school" : "school", "total_socialscience" : 152, "total_science" : 148,
        "total_language" : 202, "avg_science" : 74, "avg_socialscience" : 76, "avg_language" : 67.33333333333333 }
        { "_id" : ObjectId("5aa4bbe212899b0fde851295"), "name" : "rock", "class" : 10, "region" : "rural", "school" : "school", "total_socialscience" : 142, "total_science" : 137,
        "total_language" : 215, "avg_science" : 68.5, "avg_socialscience" : 71, "avg_language" : 71.66666666666667 }
        { "_id" : ObjectId("5aa4bbe212899b0fde851296"), "name" : "mary", "class" : 10, "region" : "urban", "school" : "school", "total_socialscience" : 162, "total_science" : 162,
        "total_language" : 210, "avg_science" : 81, "avg_socialscience" : 81, "avg_language" : 70 }

Student Appeared for exam
    db.studentinfo.aggregate([
                 { $match: { class: 10 } },
                     { $group: { _id: {"region": "$region","class": "$class"}, total: { $sum: 1 } } },
                   ])
    output:
        { "_id" : { "region" : "urban", "class" : 10 }, "total" : 3 }
        { "_id" : { "region" : "rural", "class" : 10 }, "total" : 3 }

Does student 80 or higher mark in marathi 

    db.studentinfo.aggregate(
        { $project: {
        _id: 0,
        name: 1,
        marathiFilterd: {$cond: [
                    {$gt: ['$marathi', 80]},
                    1,
                    0
                ]}
        }},
        { $group: {
        _id: "$name",
         marathiFi: {$sum: '$marathiFilterd'}
        }});

    output:
        { "_id" : "sagar", "marathiFi" : 0 }
        { "_id" : "sangram", "marathiFi" : 1 }
        { "_id" : "sachin", "marathiFi" : 0 }
        { "_id" : "mary", "marathiFi" : 0 }
        { "_id" : "rock", "marathiFi" : 1 }
        { "_id" : "swapnil", "marathiFi" : 0 }


Student with First class in marathi & english:

    db.studentinfo.aggregate(
        { $project: {
        _id: 0,
        class: 1,
        region:1,
        marathiFilterd: {$cond: [
                    {$gt: ['$marathi', 60]},
                    1,
                    0
                ]},
           englishFilterd: {$cond: [
                    {$gt: ['$english', 60]},
                    1,
                    0
                ]}
        }},
        { $group: {
        _id: {class:"$class",region:"$region"},
         marathiFi: {$sum: '$marathiFilterd'},
         englishFi: {$sum: '$englishFilterd'},
         total:{$sum:1}
        }});

output:
    { "_id" : { "class" : 10, "region" : "urban" }, "marathiFi" : 2, "englishFi" : 2, "total" : 3 }
    { "_id" : { "class" : 10, "region" : "rural" }, "marathiFi" : 3, "englishFi" : 3, "total" : 3 }

Project multiple times:

        db.studentinfo.aggregate(
            { $project: {
            _id: 0,
            class: 1,
            region:1,
            marathiFilterd: {$cond: [
                        {$gt: ['$marathi', 60]},
                        1,
                        0
                    ]},
               englishFilterd: {$cond: [
                        {$gt: ['$english', 60]},
                        1,
                        0
                    ]}
            }},
            { $group: {
            _id: {class:"$class",region:"$region"},
             marathiFi: {$sum: '$marathiFilterd'},
             englishFi: {$sum: '$englishFilterd'},
             total:{$sum:1}
            }},
                { $project:  {class : '$_id.class',region:'$_id.region',total:'$total',marathiFirstclass:'$marathiFi',englishFirstclass:'$englishFi',_id:0}}
        );


Sunday, March 4, 2018

What is call() , apply() and bind() in JavaScript ?

As functions are also Objects in JavaScript, these 3 methods are used to control the invocation of the function. call() and apply() were introduced
in ECMAScript 3 while bind() was added as part of ECMAScript 5.


call() or Function.prototype.call():

    consider following code snippet

        var obj = {name:"John"};
        var howDoYouDo = function(a,b){
            return "How are you "+ this.name + ", welcome to " + a + "," + b;
        };
        console.log(howDoYouDo.call(obj,"Pune","Maharashtra"));

    output:
        How are you John, welcome to Pune,Maharashtra


    we are using call() method on howDoYouDo(),first argument sets the "this" value, other two arguments are parameters of  greeting function in corresponding order.


apply() or Function.prototype.apply():

    consider following code snippet

        var obj = {name:"merry"};
        var howDoYouDo = function(a,b){
            return "How are you "+ this.name + ", welcome to " + a + "," + b;
        };
        var args = ["Mumbai","Maharshtra"];
        console.log(howDoYouDo.apply(obj,args));

    output:
        How are you merry, welcome to Mumbai,Maharshtra

    we are using apply() method on howDoYouDo(),first argument sets the "this" value ,other two arguments are parameters of  howDoYouDo() function in corresponding order
    passed as an array.

bind() or Function.prototype.bind():

    consider following code snippet

        var obj = {name:"saucy"};
        var howDoYouDo = function(a,b){
            return "How are you "+ this.name + ", welcome to " + a + "," + b;
        };
        var bound = howDoYouDo.bind(obj);
        console.log(bound("Nagpur","Maharshtra"));

    output:
        How are you saucy, welcome to Nagpur,Maharshtra

    Here we are creating bound function to which we passed 'this' the context but bound function can be invoked seperately at latter moment.

    Lets consider one more example for bind() function

        var getUserComments = function(callback) {
            var numOfCommets = 34;
            callback({ comments: numOfCommets });
        };
        var User = {
            fullName: 'John Black',
            print: function() {
                getUserComments(function(data) {
                        console.log(this.fullName + ' made ' + data.comments + ' comments');
                });
            }
        };
        User.print();

    output:
        undefined made 34 comments

    Here this.fullName is having value undefined inside getUserComments() function basically it is not getting desired value of 'this'.

        Lets see how we can use bind() here to fix problem

        var getUserComments = function(callback) {
                    var numOfCommets = 34;
                    callback({ comments: numOfCommets });
                };

        var User = {
            fullName: 'John Black',
            print: function() {
            console.log(this);
            getUserComments(function(data) {
                console.log(this.fullName + ' made ' + data.comments + ' comments');
            }.bind(this));
            }
        };
        User.print();


    output:
        {fullName: "John Black", print: Æ’}

        John Black made 34 comments

    Here when we are doing 'console.log(this);' inside 'print()' method ,we see that by passing it to bind on function getUserComments() ,'this.fullName' can get desired value.


How to define private property using bind in a javascript class ?
    There are no private, public or protected keywords in current ECMAScript 6 specification but we can use bind() function to define a private method/property in class.
  
    Inside democlass.js

        function privateFunc() {
            console.log("My property: " + this.property);
        }
        class MyClass {
            constructor() {
            this.property = "property_value";
            }
            callPrivateFunc() {
            var boundPrivateFunc = privateFunc.bind(this);
            boundPrivateFunc();
            }
        }
        module.exports = MyClass;  

    Inside demo.js

        var dc = require('./democlass');

        var cls =new dc();
        cls.callPrivateFunc();
        cls.privateFunc();  

     Here in 'MyClass' we are writing a method  callPrivateFunc() in which we are binding function defined outside class 'privateFunc()' to this including this module in demo.js
     Inside demo.js we are calling 'callPrivateFunc()' method of class and privateFunc() method defined outside class
    for our attempt to call 'privateFunc()' method we get an error as follows

        TypeError: cls.privateFunc is not a function

    but calling class method succeed we get result too

        My property: property_value
  
      this way we defined private method in class.

Note : print without using console ?

     process.stdout.write("hello: ");
 


Understanding Immutable,Mutable,Deep and Shallow Copy in Javascript

Immutable:
    An immutable object is an object whose state cannot be modified after it is created.Examples of native JavaScript values that are immutable are numbers and strings.

    consider following code


    let a = 'test';
    let b = a;
    a = a.substring(2);

    console.log(a);
    console.log(b);
    console.log(a === b) ;

    output:
        st
        test
        false

    Here when we assign variable a to b, b gets value of a but they do not refer to same object so changes in variable a does not reflect in variable b.

    consider one more code snippet

        let a = 1;
        let b = a;
        a++;

        console.log(a)
        console.log(b)
        console.log(a === b)
    output:
        2
        1
        false

    After assigning variable 'a' to 'b' we are incrementing variable 'a' but value of variable 'b' do not get incremented as variable 'a' & 'b' referer to different memory location.


Mutable:
    A mutable object is an object whose state can be modified after it is created.
    Examples of native JavaScript values that are mutable include objects, arrays, functions, classes, sets, and maps.

    consider following code

        let a = {
            foo: 'bar'
        };

        let b = a;

        a.foo = 'test';

        console.log(b.foo);
        console.log(a.foo);
        console.log(a === b);

    Output:
        test
        test
        true

    Though we changed 'a.foo' changes reflected in 'b.foo'.    variable a & b both references one and same so change in state of one reflect in other as both refer to same object.

    consider one more code snippet:

        const person = {
            name: 'John',
            age: 28
        }
        const newPerson = person
        newPerson.age = 30
        console.log(newPerson === person) // true
        console.log(person) // { name: 'John', age: 30 }

    output:

        true
        {name: "John", age: 30}


    Here we changed 'newPerson.age' and changes reflected in 'person.age' as they refer same object again.This is unexpected & undesired.
    if you don't want this you must create a new object and explicitly copy over the properties.

    var person = {
            name: 'John',
            age: 28
    };

    var newPerson = new Object();
    for(prop in person){
      newPerson[prop] = person[prop];
    }

    newPerson.age = 30
    console.log(newPerson === person)
    console.log(person)
    console.log(newPerson)

    output:
        false
        {name: "John", age: 28}
        {name: "John", age: 30}

    Here we copied all properties of object 'person' to 'newperson' object but both do not refer to same memory location ,so changes in one do not reflect in other.

How can we copy only value of one object to another rather than creating another reference to same object ?

    Object.assign is ES6 feature that comes to our rescue.

    Lets consider following code snippet:

        const person = {
          name: 'John',
          age: 28
        }
        const newPerson = Object.assign({}, person, {
          age: 30
        })
        console.log(newPerson == person)
        console.log(newPerson === person)
        console.log(person)
        console.log(newPerson)

    output:
        false
        false
        {name: "John", age: 28}
        {name: "John", age: 30}

When object has nexted object then deep copy fails

http://msdotnetbuddy.blogspot.com/2018/09/objectassign-in-javascipt.html

deep copy should be done with JSON.parse(JSON.stringify(obj2clone)) or using lodash-->cloneDeep() method.

Mutating Array:
    consider following code snippet

        const characters = [ 'Obi-Wan', 'Vader' ]
        const newCharacters = characters
        newCharacters.push('Luke')
        console.log(characters === newCharacters)

        output:
            true

    Here also both 'characters' array & 'newCharacters' array refer to same object.

ES6 contains a spread operator:

    with reference to previous code snippet,Es6 comes with spread feature.It is denoted by '...'.With spread ,array 'newCharacters'
    get all elements of array 'characters' and additional  array element 'Luke'.

    modified code snippet:

        const characters = [ 'Obi-Wan', 'Vader' ]
        const newCharacters = [ ...characters, 'Luke' ]
        console.log(characters === newCharacters)        
        console.log(characters)
        console.log(newCharacters)
    output:

        false
        ["Obi-Wan", "Vader"]
        ["Obi-Wan", "Vader", "Luke"]

    Here 'characters' array & 'newCharacters' array do not refer to same object.


    using spread operator on object:
   
    following code snippet

        const person = {
            name: 'John',
            age: 28
        }
        const newPerson = {
            ...person,
            age: 30
        }
        console.log(newPerson === person) // false
        console.log(newPerson) // { name: 'John', age: 30 }

    Output:
        false
        {name: "John", age: 30}
   
    Here object 'newPerson' get all properties of 'person' and additional property 'age',but 'person' already have 'age' property so object 'newPerson' get only one property with latest value i.e. 30.

Freezing Object from modification:

    consider following code snippet

        const object1 = {
          property1: 42
        };

        const object2 = Object.freeze(object1);

        object2.property1 = 33;
        console.log(object2.property1);

    output:
        42

    The Object.freeze() method freezes an object meaning it, prevents new properties from being added to it; prevents existing
    properties from being removed; and prevents the prototype from being changed.The method returns the passed object.

    Any attempt to do so fails sliently except when code is running in strict mode with 'use strict' on top,lets see the same 

        'use strict'
        const object1 = {
          property1: 42
        };

        const object2 = Object.freeze(object1);

        object2.property1 = 33;
        console.log(object2.property1);

    output:
        Uncaught TypeError:Cannot assign to read only property 'property1' of object.


How to check if object is frozen ?

    var obj = {
      foo: 'bar',
      pass:'none'   
    };

    obj.lumpy = 'woof';

    delete obj.pass;

    var o = Object.freeze(obj);

    obj.foo = 'quux';
    o.foo = 'quux';

    console.log(obj);
    console.log(o);

    Object.isFrozen(obj);

    delete obj.foo;
    console.log(obj);

output:
    {foo: "bar", lumpy: "woof"}
    {foo: "bar", lumpy: "woof"}

    in 'Object.freeze' Both the object being passed as well as the returned object are frozen.
    attempt to delete property with    'delete obj.foo;' failed silently.

Freezing an array

    Consider following code snippet

        let a = [0,5,7];
        Object.freeze(a);

        a[0]=1;
        //a.push(2);
        console.log(a);
    output:
        we get following error for line in above code
            a.push(2);
        Uncaught TypeError: Cannot add property 1, object is not extensible but line 'a[0]=1;' fails silently.

what is difference between object.seal & object.freeze ?

Object.seal:
    It prevents adding and/or removing properties from the sealed object ,however defined properties still can be changed.

    It throws a TypeError when attempting to modify in strict mode else fails silently.Using delete will return false.

    It makes every property non-configurable, and they cannot be converted from data accessors to properties and vice versa.

Object.freeze:

    Exactly what Object.seal does but additionally it prevents changing any existing properties too.

Object.preventExtensions:

    The Object.preventExtensions() method prevents new properties from ever being added to an object.

    consider following code snippet

        const object1 = {'srno':1,'deleteme':'yes'};
        Object.preventExtensions(object1);
        object1.srno =2;

        try {
          Object.defineProperty(object1, 'property1', {
            value: 42
          });
        } catch (e) {
          console.log(e);
        }
        delete object1.deleteme;
        console.log(object1);

    output:
        Attempt to define new property with 'defineProperty' result in error 'TypeError: Cannot define property property1 object is not extensible'.

      At the end object1 has value {srno: 2}.As deleting property succeed in line 'delete object1.deleteme;' as its not prevented here.Similarly modifying existing property value is allowed too hence 'srno' property becomes '2' .

       
Shallow copy:

    In shallow copy only the memory address is copied.so new object also refer to same memory address any change in property of one reflect in other.

    consider following code snippet:

        var employeeDetailsOriginal = {  name: 'Manjula', age: 25, Profession: 'Software Engineer' };
        var employeeDetailsDuplicate = employeeDetailsOriginal;
        employeeDetailsDuplicate.name = 'NameChanged';
        console.log(employeeDetailsOriginal)
    output:

        {name: "NameChanged", age: 25, Profession: "Software Engineer"}

Deep Copy:

    A deep copy copies all fields, and makes copies of dynamically allocated memory pointed to by the fields.
   
    Suppose you want to make a deep copy of object X into variable Y,With Deep Copy ,it makes a copy of all the members of X, allocates different memory location for Y
    and then assigns the copied members to Y to achieve deep copy. In this way, if X vanishes Y is still valid in the memory.

    consider following code snippet

        var employeeDetailsOriginal = {  name: 'Manjula', age: 25, Profession: 'Software Engineer' };

        var employeeDetailsDuplicate = JSON.parse(JSON.stringify(employeeDetailsOriginal));

        employeeDetailsDuplicate.name = 'NameChanged';
        console.log(employeeDetailsOriginal)
        console.log(employeeDetailsDuplicate)
    output:
        {name: "Manjula", age: 25, Profession: "Software Engineer"}
        {name: "NameChanged", age: 25, Profession: "Software Engineer"}

    Here change in 'employeeDetailsDuplicate.name' does not reflect in 'employeeDetailsOriginal.name' as both point to different memory location.our trick below made deep copy of object concerned

        var employeeDetailsDuplicate = JSON.parse(JSON.stringify(employeeDetailsOriginal));

    Point to note is in Shallow copying only new reference is created for existing object but old & new copy point to same object.

On performance point of view deep copying create new object ,creating new objects is time and memory consuming ,it do comes with a bit more overhead but advantages outweigh.

    Making sure your state is immutable forces you to think better of your application structure.Reduces the possibility of nasty bugs.you can just rely on oldObject === newObject to check if state changed or not, this is way less CPU demanding.

Saturday, March 3, 2018

Exploring Express.js Features

Express.js comes with lot of feature ,lets explore them step by step


what is res.locals in express.js ?

    An object that contains response local variables scoped to the request, and therefore available only to the view(s) rendered during that request / response cycle (if any).
    This property is useful for exposing request-level information such as the request path name, authenticated user, user settings, and so on.
    e.g.
        app.use(function(req, res, next){
          res.locals.user = req.user;
          res.locals.authenticated = ! req.user.anonymous;
          next();
        });

what is app.locals in express.js ?

    The app.locals object has properties that are local variables within the application.Once set, the value of app.locals properties persist throughout the life of the application.You can access     local variables in templates rendered within the application. This is useful for providing helper functions to templates, as well as application-level data. Local variables are available in         middleware via req.app.locals.
    e.g.
        app.locals.title = 'My App';
        app.locals.strftime = require('strftime');
        app.locals.email = 'me@myapp.com';
   
    in contrast with res.locals properties defined in app.locals are valid only for the lifetime of the request.


How to remove 'x-powered-by' header:
 
    to remove certain header you can use 'res.removeHeader' using a custom middleware or can use 'app.disable'.
    e.g.
        app.use(function (req, res, next) {
          res.removeHeader("X-Powered-By");
          next();
        });

            or

        app.disable('x-powered-by');

    try to hit some route say GET for simplicity in POSTMAN and check below header is present on response
        X-Powered-By →Express

How to enable case-sensitive routing:Inside our router definition we can pass 'caseSensitive=true'
    var router = express.Router({
      caseSensitive: true
    });

    other approach described below,but found to be not working
   
    app.disable('case sensitive routing',false);

    by making route case-sensitive we end up in /login is not same as /LOGIN.so you will get 404 for /LOGIN if you defined only /login

Unhandled error:
     In express router if we get an error and its not handled then it trickle to app level.

consider below route

router.get('/uncaught', function (req, res,next) {
  var Promise = require('bluebird');
  var Pgb = require("pg-bluebird");
  var pgb = new Pgb();
  var connectionString = 'postgres://xdba:sangram@localhost:5432/xplay';
  var cnn;

  var query1 = 'select * from tbl_nowhere where channel_id=1';
  console.log(query1);
  return pgb.connect(connectionString)
    .then(function (connection) {
      cnn = connection;
      return cnn.client.query(query1);
    }).then(function (result) {
      return result;
      cnn.done();
    })
    .catch(function (error) {
      throw error;
      //next(error);
    });
});

we are purposefully giving wrong table name in query so that we get an error 'relation "tbl_nowhere" does not exist'.


when I am throwing an error in catch block it has been observed that request does not halt,now let's replace 
'throw error' by 'next(error)'.

Now error trickle down to app.js.To catch this unhandled error express.js uses middleware.usually at bottom of app.js.here is how it looks like.


app.use(function (err, req, res, next) {
  console.log('Env:' + app.get('env'));
 
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});


what it does is check if application is running in developement mode or not,if it is running in development mode then it loads error view with message & stacktrace.
On production enviornment we usually don't show such errors to client but log them somewhere and show some generic error to user.
   

Thursday, March 1, 2018

Exploring CRUD operation in mongo Part I


we need a collection on which we can run our mongo queries.Lets create a collection for the same.

One can create a mongo collection using 'createCollection' function as follows


    db.createCollection("crudops")


lets add some dummmy data into this collection as follows


    db.crudops.insert({"name":"Samsung Galaxy Note 1","ram":2,"os":"Jelly Bean","company":"samsung india","display":"gorilla glass"})

    db.crudops.insert({"name":"Samsung Galaxy S9 +","ram":6,"os":"Oreo","company":"samsung india","display":"Super AMOLED"})

    db.crudops.insert({"name":"iPhone x","ram":3,"os":"iOS 11.1.1","company":"Apple india","display":"Super AMOLED"})

    db.crudops.insert({"name":"Oppo A17","ram":4,"os":"Nougat","company":"Oppo india","display":"IPS LCD"})

    db.crudops.insert({"name":"Google Pixel 2","ram":4,"os":"Oreo","company":"Google india","display":"AMOLED"})

    db.crudops.insert({"name":"Google Pixel XL","ram":4,"os":"Oreo","company":"Google india","display":"AMOLED"})


we can search all document for samsung india as follows

    db.crudops.find({company: "samsung india"},{}).pretty()

Lets explore some CRUD functionality

1) findAndModify:
 Here findAndModify return value of record before update.'findAndModify' doesn't allow updating multiple documents at a time.

    you can only update one document and it returns the original doc by default.

        Query:

            db.crudops.findAndModify({

                query: { company: "samsung india"},

                sort: { ram: 1 },

                update: { company: "samsung" } ,

                upsert: false

            })


        output:

            { "_id" : ObjectId("5a98118839eb5b1254451ec5"), "company" : "samsung india" }


    Returning updated document:

       Here we are setting 'new' as true so we are getting updated record.default value of 'new' is false.

        Query:

            db.crudops.findAndModify({

                    query: { company: "samsung india"},

                    sort: { ram: 1 },

                    update: { company: "samsung" } ,

                    upsert: false,

                    new: true

                })

        output:

            { "_id" : ObjectId("5a9811d339eb5b1254451ec6"), "company" : "samsung" }

Here in above two 'findAndModify' operations update field is replacing entire document with value specified for 'update' to update particular field we need to use $set

db.crudops.findAndModify({
        query: { company: "Google"},
        sort: { ram: 1 },
        update:  { $set: {"company": "Google INC" } },
        upsert: false,
        new: true
    })

Old Record:
    {
        "_id" : ObjectId("5a9812fa39eb5b1254451eca"),
        "name" : "Google Pixel XL",
        "ram" : 4,
        "os" : "Oreo",
        "company" : "Google",
        "display" : "AMOLED"
    }


New Record:
{
    "_id" : ObjectId("5a9812fa39eb5b1254451eca"),
    "name" : "Google Pixel XL",
    "ram" : 4,
    "os" : "Oreo",
    "company" : "Google INC",
    "display" : "AMOLED"
}

Here only field 'company' is updated rather than replacing entire document except _id.

2) update:

    with 'update' we can update multiple document matching criteria in single query but we need to set  'multi: true', so that multiple documents matching filter get updated otherwise default behaviour is to update only one.


    Query:  

        db.crudops.update(

          {company: "Google india"},

          {

            $set: {

              "company": "Google"

            }

          },

         {

             upsert: false,

             multi: true,

         }

        );


    output:

        WriteResult({ "nMatched" : 2, "nUpserted" : 0, "nModified" : 2 })


   

        we can cross-verify update result with

        db.crudops.find({company: "Google"},{}).pretty()


3)Findoneandupdate:

    Query:  

        db.crudops.findOneAndUpdate(

                {company: "Google"},

                {$set: {"company": "google"}},

                    {sort : { "name" : 1 } }

            )


    Output:Old record is returned by default

        {

            "_id" : ObjectId("5a9812c839eb5b1254451ec9"),

            "name" : "Google Pixel 2",

            "ram" : 4,

            "os" : "Oreo",

            "company" : "Google",

            "display" : "AMOLED"

        }


    returning new record

        'returnNewDocument : true' is needed for returing updated document.

         Query:  

           db.crudops.findOneAndUpdate(

               { "name" : "Google" },

               { $set: { "name" : "google"} },

               { sort: { "name" : 1 }, upsert:true, returnNewDocument : true }

            );


         Output:

            { "_id" : ObjectId("5a981ed7cf26fba5c0340b10"), "name" : "google" }


w.r.t.  findAndModify & update,update first fetch the item first and then updates it unlike 'findAndModify'.If we fetch an item and then update it, there may be an update by another thread between those two steps. If you update an item first and then fetch it, there may be another update in-between and you will get back a different item than what you updated.Doing it "atomically" means you are guaranteed that you are getting back the exact same item you are updating - i.e. no other operation can happen in between this is ensured by 'findAndModify',also 'findAndModify' returns the document, update does not.    Furthermore 'findAndModify' is deprecated for 'findOneAndUpdate'.

4) _id Primary Key of document:
Each document we insert into collection get additional field called _id which is combination of timestamp,machine key & process id & some additional binary number.But if you insert a document with _id field then default field get overwritten.

    Query:
        db.crudops.insert({_id:5}) and 
        db.crudops.insert({id:5})
    output:
        { "_id" : ObjectId("5a98dbb7b819cf73e0a44af1"), "id" : 5 }
        { "_id" : 5 }

5) deleteOne:
    Record to Delete:
        { "_id" : 5 }
    Query:
        db.crudops.deleteOne({"_id" : 5});
    Output:
        { "acknowledged" : true, "deletedCount" : 1 }


deleteOne deletes the first document that matches the filter. Need tp use a field that is part of a unique index such as _id for precise deletions.
    deleteOne() throws a WriteError exception if used on a capped collection. To remove documents from a capped collection, use db.collection.drop() instead.

6) deleteMany:
    deleteMany() also throws a WriteError exception if used on a capped collection. To remove all documents from a capped collection, use db.collection.drop() instead.

    Query:
    try {
       db.crudops.deleteMany( { "display" : "AMOLED" } );
    } catch (e) {
       print (e);
    }
    Output:
    { "acknowledged" : true, "deletedCount" : 2 }

    Here following two document get deleted
    {
        "_id" : ObjectId("5a9812c839eb5b1254451ec9"),
        "name" : "Google Pixel 2",
        "ram" : 4,
        "os" : "Oreo",
        "company" : "google",
        "display" : "AMOLED"
    }
    {
        "_id" : ObjectId("5a9812fa39eb5b1254451eca"),
        "name" : "Google Pixel XL",
        "ram" : 4,
        "os" : "Oreo",
        "company" : "Google INC",
        "display" : "AMOLED"
    }

7) remove:
By default, remove() removes all documents that match the query expression. Specify the justOne option to limit the operation to removing a single document. To delete a single document sorted by a         specified order, use the findAndModify() method.

        Query:
            db.crudops.remove({"company": "samsung"},true)
        output:
            WriteResult({ "nRemoved" : 1 })

    to remove all document matching filter
   
        Query:
            db.crudops.remove({ company: "google" },false)
        Output:
            WriteResult({ "nRemoved" : 8 })


     using 'findAndModify' to remove
    lets add some documents
        db.crudops.insert({"company":"google","sortindex":"1"});
        db.crudops.insert({"company":"google","sortindex":"2"});
        db.crudops.insert({"company":"google","sortindex":"3"});
        db.crudops.insert({"company":"google","sortindex":"4"});
        db.crudops.insert({"company":"google","sortindex":"5"});
        db.crudops.insert({"company":"google","sortindex":"6"});

    Query:
        db.crudops.findAndModify({
            query: { company: "google" },
            sort: { sortindex: 1 },
            remove: true,
            upsert:false
        })
    output:
        {
            "_id" : ObjectId("5a98e1cdb819cf73e0a44af2"),
            "company" : "google",
            "sortindex" : "1"
        }

    Here records get sorted by sortindex then first record is removed.

8) findOneAndDelete:
It deletes a single document based on the filter and sort criteria, returning the deleted document.
   
    Query:
        db.crudops.findOneAndDelete(
            { "company" : "google" },
            { sort : { "sortindex" : -1 } }
        )
    output:
        {
            "_id" : ObjectId("5a98e1f7b819cf73e0a44af5"),
            "company" : "google",
            "sortindex" : "4"
        }   

    Here also one record deleted but sort order specified is descending.

findOneAndDelete() returns the deleted document after having deleted it in case you need its contents after the delete operation.
    deleteOne() is used to delete a single document while remove() is a deprecated function and has been replaced by deleteOne() to delete a single document and deleteMany() to delete multiple documents.

9) findOneAndReplace:
    Query:
        db.crudops.findOneAndReplace(
           { "company" : "google" },
           { "display" : "AMOLED", "Ram" : 4 },
           { sort: { "sortindex" : 1 } }
        )
    Output:
        It return document before update
        {
            "_id" : ObjectId("5a98e1d3b819cf73e0a44af3"),
            "company" : "google",
            "sortindex" : "2"
        }

    after this update the updated document is

        {
            "_id" : ObjectId("5a98e1d3b819cf73e0a44af3"),
            "display" : "AMOLED",
            "Ram" : 4
        }
    the filter field also get removed as not specified in replace string

    returning updated document in findOneAndReplace:

    Query:
        db.crudops.findOneAndReplace(
           { "company" : "google" },
           { "company" : "google","display" : "AMOLED", "Ram" : 40 },
           { sort: { "sortindex" : 1 },returnNewDocument:true}
        )
    Output:
        {
            "_id" : ObjectId("5a98e1f4b819cf73e0a44af4"),
            "company" : "google",
            "display" : "AMOLED",
            "Ram" : 40
        }

    complete document after update is
        {
            "_id" : ObjectId("5a98e1f4b819cf73e0a44af4"),
            "company" : "google",
            "display" : "AMOLED",
            "Ram" : 40
        }

10) insertmany:
    Given an array of documents, insertMany() inserts each document in the array into the collection.By default documents are inserted in order.If ordered is set to false, documents are inserted in an unordered format and may be reordered by mongod to increase performance.
   
    Query:
        db.crudops.insertMany(
            [
                {"company":"google","sortindex":"7"},
                {"company":"google","sortindex":"8"},
                {"company":"google","sortindex":"9"}
            ],
            { ordered: false }
        );
    Output:
    {
        "acknowledged" : true,
        "insertedIds" : [
            ObjectId("5a98e8cdb819cf73e0a44af8"),
            ObjectId("5a98e8cdb819cf73e0a44af9"),
            ObjectId("5a98e8cdb819cf73e0a44afa")
        ]
    }   

   we can insert primary key _id field also

    db.crudops.insertMany(
            [
                {"company":"google","sortindex":10,_id: 10},
                {"company":"google","sortindex":11,_id: 11},
                {"company":"google","sortindex":12,_id: 12}
            ],
            { ordered: false }
        );
    output:
        { "acknowledged" : true, "insertedIds" : [ 10, 11, 12 ] }

    db.crudops.insertMany(
            [
                {"company":"google","sortindex":10,_id: 12},
                {"company":"google","sortindex":11,_id: 13},
                {"company":"google","sortindex":12,_id: 14}
            ],
            { ordered: false }
        );

Here we are trying to insert a duplicate key in _id with 12 which resulted in error but remaining two records get inserted.so you can find following records despite error as these two record does not violate any constraint as such.

        {"company":"google","sortindex":11,_id: 13},
        {"company":"google","sortindex":12,_id: 14}

Error message for first record is "E11000 duplicate key error collection: Northwind.crudops index: _id_ dup key: { : 12.0 }".

Note:To clear mongo console you can use 'cls' command.

Javascript var vs let vs const & Hoisting

In JavaScript we can define variable with var .
With ES6 we can also define variable with let & const.

There is subtle difference in scope of variable defined with var & let.
There is further difference due to hoisting behaviour for var in javascript.

declaration of variable using var keyword:
var keyword is used in JavaScript to declare a variable along with
optional initialization of variable.
e.g.
var x=10;
or
var t;

The scope of a JavaScript variable declared with var is its current
execution context while the scope of a JavaScript variable declared
outside the function is global.

Code:
function varScopeDemo(){
var x ='initial';
console.log(x);

if(1==1)
{
var x='first';
console.log(x);
}
console.log(x);
}

Output:

initial
first
first

This behavior is specific to the var keyword in JavaScript,
where variables declared using var are function-scoped
rather than block-scoped.
This means that variables declared with var are accessible throughout
the entire function, regardless of where they are declared within the
function.

Now lets replace var in our function with 'let'

Code:

function letScopeDemo(){
let x ='initial';

console.log(x);
if(1==1){
let x='first';
console.log(x);
}
console.log(x);
}

Output:
initial
first
initial

'let' create a variable with the scope limited to the block on which it is used
that is why console.log outside if block has value assigned before if block &
not from if block initialization.

This behavior is specific to the let keyword in JavaScript,
which introduces block-scoped variables. Variables declared
using let are only accessible within the block in which they
are declared or in nested blocks. They do not override variables
with the same name declared in outer scopes.

Now lets move to 'const'.

Code:
function constScopeDemo(){
const x ='initial';

console.log(x);
if(1==1){
const x='first';
console.log(x);
}
console.log(x);
}

Output:
initial
first
initial

in terms of scope 'const' are same as 'let'


Reassignment to constant variable:

Now let us try another code snippet

Code:

function constScopeDemo(){
const x ='initial';

console.log(x);
if(1==1){
x='first';
console.log(x);
}
console.log(x);
}

Output:
Uncaught TypeError: Assignment to constant variable.

Here when we try to execute 'constScopeDemo' function we get an error because
'const' statement can assign value once and they cannot be reassigned.


we need to assign value to variable defined with const else it result in an
error.below line when execute result in error

Code:
const name;

Output:
Missing initializer in const declaration.


Redeclaration of variable in same scope using var:
Consider following code snippet

Code:
function varScopeDemo() {
var x = "initial"; // Declare and initialize x as "initial"
var x = "second"; // Redeclare x as "second"
console.log(x); // Output: second
}
Output:
second

Explanation:
In JavaScript, using the var keyword allows you to redeclare variables
within the same scope without causing an error. However, it's important
to note that redeclaring a variable with var effectively overrides the
previous declaration.

Redeclartion of variable in same scoper using let.

Code:
function letScopeDemo() {
let x = "initial";
let x = "second";
console.log(x);
}

Output:
Identifier 'x' has already been declared

Explanation:
In JavaScript, when using the let keyword to declare variables,
redeclaring a variable with the same name in the same block scope
results in a syntax error.

Global Declaration of variable:
Consider following code snippet

Code:
t=10
console.log(t)
Output:
10

Explanation:
t = 10; assigns the value 10 to t.
Since t is not explicitly declared using var, let, or const,
it becomes a global variable by default.

JavaScript will treat t as a global variable.if you're in a browser
environment; In Node.js, it would be a module-level variable.

Hoisting in javascript:

Hoisting is JavaScript's default behavior of moving all declarations to the
top of the current scope.JavaScript only hoists declarations, not
initializations.

Consider following code snippet

Code:
var x = 8;
console.log(x + " " + y + " " + t);
var y = 64;

Output:
Uncaught ReferenceError: t is not defined

Explanation:
here t is neither declared using var nor by let or const.nor is it a global
variable.

Now lets modify this snippet little bit

Code:
var x = 8;
console.log(x + " " + y );
var y = 64;

Output:
8 undefined

Here y is defined after its use in console.log but due to Hoisting
its declaration is taken up in snippet so when we go to console.log
statement variable is defined but it has value undefined because
initialization is not hoisted.

Lets check hoisting behavior with 'let',in following code snippet
again 'y' is declared after use.

Code:
let x = 8;
console.log(x + " " + y );
let y = 64;


Output:
Uncaught ReferenceError: y is not defined

Here we not getting 'y' with undefined value as variable 'y' is not yet defined.
Hoisting does not happen when variable defined with let & const.

Hoisting & global variable:
Consider following code snippet

Code:
console.log(t)
t=10

Explanation:
Even if t is global variable,we can't use it before declaration.Hoisting
does not happen here.

Output:
ReferenceError: t is not defined


Mixing var & let
Consider code snippet below

Code:
let count = 40;
var count = 30;

Output:
Identifier 'count' has already been declared

This happen irrespective of let comes first or var comes first.

Closure :
Consider code snippet below

Code:
for (var i = 0; i < 5; ++i) {
console.log('log:' + i);
setTimeout(function () {
console.log(i);
}, 100);
}

Output:
5 5 5 5 5

on contratory

Code:
for (let i = 0; i < 5; ++i) {
console.log('log:' + i);
setTimeout(function () {
console.log(i);
}, 100);
}

Output:0 1 2 3 4

Explanation:
There is difference in behavior between let & var because ,
the let in the loop can re-binds it to each iteration of the loop,
making sure to re-assign it the value from the end of the previous
loop iteration.