Search This Blog

Monday, October 8, 2018

Javascript : Array - map ,reduce,filter


Map, Reduce and Filter are Array methods each one will iterate over an array
and perform a transformation or computation.They are all 'higher order'
functions because they take user-defined functions as parameters.


Map:
The map() method is used for creating a new array from an existing one by
applying a callback function to each one of the elements of the first array.

Detailed Syntax for map function in javascript is

array.map(callback(currentValue, index, array), thisArg)

or

array.map((currentValue, index, array)={
//operate on input & return
}, thisArg)

Here's what each part of the syntax represents:

array: The array on which the map() method is called.

callback: A function that will be called once for each element in the
array.It can take up to three arguments:

currentValue: The current element being processed in the array.

index (optional): The index of the current element being processed.

array (optional): The array map() was called upon.

thisArg (optional): An optional parameter that defines the value to be
used as this inside the callback function.

Code:
const person = {
firstName: "John",
lastName: "Doe",
fullName() {
return this.firstName + " " + this.lastName;
},
};

const people = [
{ firstName: "Alice", lastName: "Smith" },
{ firstName: "Bob", lastName: "Johnson" },
];

const fullNames = people.map(function (item) {
return (
this.fullName() + " works with " + item.firstName + " "
+ item.lastName
);
}, person); // Here, 'person' is passed as the 'thisArg'

console.log(fullNames);
Output:
[
'John Doe works with Alice Smith',
'John Doe works with Bob Johnson'
]
Explanation:
Here person is passed as the 'thisArgs',so when this.fullName() is called
it do all calculation based on person object.

In common uses of map() the 'thisArgs' is rarely passed also index,array
argument are also rare.

Below are common use cases on map().

First Creating Function and then passing it to map() function as callback:
Code:
var arr=[16,25,36,49,64]

function sqrRoot(item){
return Math.sqrt(item)
}

var result = arr.map(sqrRoot)
console.log(result)

Output:
[ 4, 5, 6, 7, 8 ]

Passing callback function to map() function without creating it seperately:
Code:
var arr = [16, 25, 36, 49, 64];

var result = arr.map(function sqrRoot(item) {
return Math.sqrt(item);
});

console.log(result);
Output:
[ 4, 5, 6, 7, 8 ]

Passing a ananomous function as callback to map() function:
Code:
var arr = [16, 25, 36, 49, 64];

var result = arr.map(function(item) {
return Math.sqrt(item);
});

console.log(result);
Output:
[ 4, 5, 6, 7, 8 ]

Passing a lambda function as callback to map() function
Code:
var arr = [16, 25, 36, 49, 64];
var result = arr.map((item) => Math.sqrt(item));

console.log(result);
Output:
[ 4, 5, 6, 7, 8 ]

same lambda function can be written with a block of code enclosed in
curly braces, and return statement.

Code:
var arr = [16, 25, 36, 49, 64];
var result = arr.map((item) => {
return Math.sqrt(item)
});
console.log(result);
Output:
[ 4, 5, 6, 7, 8 ]


Note:
The result of map() is always a new array, not an object.
To transform an array into an object, you would typically
use other methods like reduce()

Reduce:
The reduce() method reduces an array of values down to just one value.
To get the output value, it runs a reducer function on each element of
the array.

Here's the syntax for the reduce() method:

array.reduce(callback(accumulator, currentValue, index, array), initialValue)

or

array.reduce((accumulator, currentValue, index, array)=.{
//do some acttion & return
}, initialValue)

Here's what each part of the syntax represents:
array: The array on which the reduce() method is called.

callback: A function that will be called once for each element in the
array,taking up to four arguments:

accumulator: The accumulator accumulates the callback's return values.
It is the accumulated value previously returned in the last invocation
of the callback,or initialValue if provided.

currentValue: The current element being processed in the array.

index (optional): The index of the current element being processed.

array (optional): The array reduce() was called upon.

initialValue (optional): A value to use as the initial value of the
accumulator. If not provided, the first element in the array will be
used as the initial accumulator value and skipped as the currentValue.

Below is an example of reduce() function.

Code:
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, currentValue) => {
return accumulator + currentValue;
}, 10);
console.log(sum);

Output:
25

Explanation:
Here accumulator has initial value of 10,in each interation
currentvalue is getting added to accumulator value.

Here are some variants of same code
Variant 1:
Code:
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, currentValue) => {
accumulator = accumulator + currentValue;
return accumulator
}, 10);
console.log(sum);
Output:
25

Variant2:
Code:
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, currentValue) => {
return accumulator = accumulator + currentValue;
}, 10);
console.log(sum);
Output:
25
reduce() can be used to transform an array of strings into a single object
that shows how many times each string appears in the array.

Code:
let pets = ["dog", "chicken", "cat", "dog", "chicken", "chicken", "rabbit"];

let petCount = pets.reduce((accumulator, currentValue) => {
if (accumulator[currentValue] == undefined) {
accumulator[currentValue] = 1;
} else {
accumulator[currentValue] = accumulator[currentValue] + 1;
}
return accumulator
}, {});

console.log(petCount);
Output:
{ dog: 2, chicken: 3, cat: 1, rabbit: 1 }

Here is another example of reduce

Code:
let pets = [
["dog", "med"],
["chicken", "feathury"],
["cat", "bil"],
["dog", "bob"],
["chicken", "minny"],
["chicken", "shelly"],
["rabbit", "binny"],
];

let petCount = pets.reduce((accumulator, currentValue) => {
var elem = {"type":currentValue[0],"name":currentValue[1]}
accumulator.push(elem)
return accumulator;
}, []);

console.log(petCount);

Output:
[
{ type: 'dog', name: 'med' },
{ type: 'chicken', name: 'feathury' },
{ type: 'cat', name: 'bil' },
{ type: 'dog', name: 'bob' },
{ type: 'chicken', name: 'minny' },
{ type: 'chicken', name: 'shelly' },
{ type: 'rabbit', name: 'binny' }
]

You can use the reduce() method in JavaScript to convert an array into an
object by accumulating key-value pairs from the array elements.

Here's an example of how to do that:
Code:
const array = [
{ key: 'name', value: 'John' },
{ key: 'age', value: 30 },
{ key: 'city', value: 'New York' }
];

const obj = array.reduce((acc, item) => {
acc[item.key] = item.value;
return acc;
}, {});

console.log(obj);

Output:
{ name: 'John', age: 30, city: 'New York' }

Filter:
The filter() method takes each element in an array and it applies
a conditional statement against it. If this conditional returns
true, the element gets pushed to the output array. If the
condition returns false, the element does not get pushed to
the output array.

Syntax of filter method:

array.filter(callback(element, index, array), thisArg)
or
array.filter((element, index, array)=>{
//do something with input & return
}, thisArg)

Here's what each part of the syntax represents:

array: The array on which the filter() method is called.
callback: A function that will be called once for each
element in the array, taking up to three arguments:
element: The current element being processed in the array.

index (optional): The index of the current element being processed.

array (optional): The array filter() was called upon.

thisArg (optional): An optional parameter that defines the value to
be used as this inside the callback function.

Example of filter with thisArg:
Code:
const numbers = [1, 2, 3, 4, 5];
const thresholdFilter = numbers.filter(function(element) {
return element > this.threshold;
}, { threshold: 3 });
console.log(thresholdFilter); // Output: [4, 5]
Output:
[4,5]
Explanation:
Here thisArg is { threshold: 3 }.we can get value from thisArg in callback
function inside this.If callback function is not normal function but arrow
function them we will not get anything in this hence it is undefined.

Doing same code using lambda function:
Code:
const numbers = [1, 2, 3, 4, 5];
// Create an object with the threshold property
const context = { threshold: 3 };
const thresholdFilter = numbers.filter((element) => {
return element > context.threshold;
});

console.log(thresholdFilter); // Output: [4, 5]
Output:
[4,5]

Explanation:
Here we are not passing thisArg instead we are using a context object
defined in outer scope
Common example of reduce:
Code:
const numbers = [1, 2, 3, 4, 5];
var even = numbers.filter((m) => {
return m % 2 == 0;
});
console.log(even);
Output:
[2,4]

Explanation:
numbers array get filtered we get even as for any number(m), m%2==0
only when it is even.

Saturday, October 6, 2018

REST Based CRUD API for Postgres & Express.js

Lets first create table in database required in article.


create table course(id varchar(50),name varchar(500),primary key(id))

insert into course values(1,'C'),(2,'CPP'),(3,'C#'),(4,'python'),(5,'Ruby')



now create PgUtil.js


const pgp = require('pg-promise')(/* initialization options */);


const cn = {

host: 'localhost', // server name or IP address;

port: 5432,

database: 'sangram',

user: 'xdba',

password: 'sangram'

};

const db = pgp(cn); // database instance;



var PgUtil = {

executeQuery: async function (sqlQuery, callback) {

var result = await db.any(sqlQuery)

console.log(result);

callback(null,result)

},


executeNonQuery: async function (sqlQuery, callback) {

var result = await db.none(sqlQuery)

console.log(result);

callback(null,result)

}

}


module.exports = PgUtil




Inside routes add course.js

var express = require('express');

var router = express.Router();

var PgUtil = require('../PgUtil');




/*getbyid */

router.get('/:id?', function (req, res, next) {

var queryString = ''

if (req.params.id) {

queryString = "select * from course where id= '" + req.params.id + "'"

} else {

queryString = "select * from course "

}

console.log(queryString);

PgUtil.executeQuery(queryString, function (err, data) {

if (err) {

res.json(err);

} else {

res.json(data)

}

})



});


/*update*/

router.put('/:id', function (req, res, next) {

console.log(req.body);

var queryString = "update course set name='" + req.body.Name + "' where id= '" + req.params.id + "'"

PgUtil.executeNonQuery(queryString, function (err, data) {

if (err) {

res.json(err);

} else {

res.json({

"message": "row updated successfully"

})

}

})



});


//insert

router.post('/', function (req, res, next) {

var queryString = "insert into course(id,name) values('" + req.body.Id + "','" + req.body.Name + "')"

console.log(queryString);


PgUtil.executeNonQuery(queryString, function (err, data) {

if (err) {

res.json(err);

} else {

res.json({

"message": "row inserted successfully"

})

}

})

});


/*delete */

router.delete('/:id', function (req, res, next) {

var queryString = "delete from course where id= '" + req.params.id + "'"

console.log(queryString);

PgUtil.executeNonQuery(queryString, function (err, data) {

if (err) {

res.json(err);

} else {

res.json({

"message": "row deleted successfully"

})

}

})

});


module.exports = router;




Now we are done ,run "npm start"


On Postman


1) GET : http://localhost:3000/course

will list all course

2) GET :http://localhost:3000/course/1

will list course with id 1

3) POST:http://localhost:3000/Course

Header:Content-Type:application/json

Body:

{

"Id":"7",

"Name":"Java"

}

will add new course

4)PUT:http://localhost:3000/Course/4

Header:Content-Type:application/json

Body:

{

"Name":"Java"

}

will update course with id 4 its name to java from old value


5) Delete: http://localhost:3000/Course/5

will delete course record with id as 5


Code of this article can be viewed at https://github.com/gitsangramdesai/express-pg-rest

REST Based CRUD API for Mysql & Express.js

First we will create a table in mysql for purpose of mysql crud demonstration.

CREATE TABLE IF NOT EXISTS `course` (  `Id` varchar(50) NOT NULL,  `Name` varchar(500) DEFAULT NULL,  PRIMARY KEY (`Id`)  ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Add Some Entries into course table

    insert into course values(1,'C');
    insert into course values(2,'CPP');
    insert into course values(3,'C#');
    insert into course values(4,'Python');
    insert into course values(5,'Ruby');
    insert into course values(6,'Java');


create express project by  running
     express --view=ejs mysqlcrud

install packages with
    npm install

Now
      dbconnection.js as follows

    var mysql = require('mysql');
    var connection = mysql.createPool({
        host: 'localhost',
        user: 'xdba',
        password: 'Sangram@123',
        database: 'play'
    });
    module.exports = connection;

Create a folder called models and add file "Course.js" with following content

var db = require('../dbconnection'); //reference of dbconnection.js

    var Course = {
        getAllCourses: function (callback) {
        return db.query("Select * from course", callback);
        },
        getCourseById: function (id, callback) {
        return db.query("select * from course where Id=?", [id], callback);
        },
        addCourse: function (Course, callback) {
        return db.query("Insert into course values(?,?)", [Course.Id, Course.Name], callback);
        },
        deleteCourse: function (id, callback) {
        return db.query("delete from course where Id=?", [id], callback);
        },
        updateCourse: function (id, Course, callback) {
        return db.query("update course set Name=? where Id=?", [Course.Name, id], callback);
        }
    };
    module.exports = Course;


add file course.js in route folder as
    var express = require('express');
    var router = express.Router();
    var Course = require('../models/Course');


    /*getbyid */
    router.get('/:id?', function (req, res, next) {
      if (req.params.id) {
        Course.getCourseById(req.params.id, function (err, rows) {
          if (err) {
        res.json(err);
          } else {
        res.json(rows);
          }
        });
      }else {
        Course.getAllCourses(function (err, rows) {
          if (err) {
        console.log("error");
        res.json(err);
          } else {
        res.json(rows);
          }
        });
      }
    });

    /*save new */
    router.post('/', function (req, res, next) {
      console.log(req.body);
      Course.addCourse(req.body, function (err, count) {
        if (err) {
          res.json(err);
        } else {
          res.json(req.body);//or return count for 1 & 0
        }
      });
    });

    /*delete */
    router.delete('/:id', function (req, res, next) {
      Course.deleteCourse(req.params.id, function (err, count) {
        if (err) {
          res.json(err);
        } else {
          res.json(count);
        }
      });
    });

    /*update*/
    router.put('/:id', function (req, res, next) {
      Course.updateCourse(req.params.id, req.body, function (err, rows) {
        if (err) {
          res.json(err);
        } else {
          res.json(rows);
        }
      });
    });

    module.exports = router;

in app.js below "var users = require('./routes/users');" add

    var course = require('./routes/course');
and in app.js below "app.use('/users', users);" add
    app.use('/course', course);

Now we are done ,run "npm start"


On Postman

1) GET : http://localhost:3000/course
    will list all course
2) GET :http://localhost:3000/course/1
    will list course with id 1
3) POST:http://localhost:3000/Course
   Header:Content-Type:application/json
   Body:
    {
    "Id":"7",
    "Name":"Java"
    }
   will add new course
4)PUT:http://localhost:3000/Course/4
   Header:Content-Type:application/json
   Body:
    {
    "Name":"Java"
    }
   will update course with id 4 its name to java from old value

5) Delete: http://localhost:3000/Course/5
    will delete course record with id as 5

code sample can be viewed at  https://github.com/gitsangramdesai/mysql-crud-express


Sunday, September 30, 2018

Express.js : Mongo as session store


    Inside app.js from express.js

    just after

        var express = require('express');
    add
        var session = require('express-session');
        const mongoose = require('mongoose');
        const MongoStore = require('connect-mongo')(session);

        mongoose.connect('mongodb://localhost/sessionstore', {
           
        });

        mongoose.Promise = global.Promise;
        const db = mongoose.connection
    then at first app.use add
        app.use(session({
          secret: 'my-secret',
          resave: false,
          saveUninitialized: true,
          store: new MongoStore({ mongooseConnection: db })
        }));

    inside some route try to save session

        req.session.city = 'Mumbai';
      req.session.username = 'sangram';

    inside another route try to retreive saved value

              console.log(req.session.city)
       console.log(req.session.username)

    to check data is saved in mongo ,connect to mongo and switch database and check

    > show collections
    sessions

    > db.sessions.find().pretty()
    {
        "_id" : "yAuqRI1gIxFOHUbxpxjGasiK61ZvrWT-",
        "session" : "{\"cookie\":{\"originalMaxAge\":null,\"expires\":null,\"httpOnly\":true,\"path\":\"/\"},\"city\":\"Mumbai\",\"username\":\"sagar\"}",
        "expires" : ISODate("2018-10-14T05:32:38.869Z")
    }

Code of article can be viewed at https://github.com/gitsangramdesai/mongo-sessionstore-express

Sunday, September 23, 2018

Node.js:Global objects

Global objects in node.js are accessible in all module without need to include them.those can be
modules, functions, strings and object.

a) __filename:absolute path of the current module file

b) _dirname:absolute path of the dir in which executable resides

    for test.js inside /home/sangram/workspace/node/global folder.
        console.log(__filename);
        console.log(__dirname);


    sangram@sangram-HP-Laptop-15-bs0xx:~/workspace/node/global$ node test.js
    /home/sangram/workspace/node/global/test.js
    /home/sangram/workspace/node/global

c) setTimeout(cb, ms):its a global function used to run callback after at least said milliseconds.A timer cannot span more than 24.8 days

    inside our test.js
        console.log(__filename);
        console.log(__dirname);

        function Hello(){
               console.log( "Hello, World!");
            }

        setTimeout(Hello, 5000);
        console.log("Reached End of File");

    running test.js
        sangram@sangram-HP-Laptop-15-bs0xx:~/workspace/node/global$ node test.js
        /home/sangram/workspace/node/global/test.js
        /home/sangram/workspace/node/global
        Reached End of File
        Hello, World!

d) clearTimeout(t): global function used to stop a timer that was previously created with setTimeout()

        inside test.js

        console.log(__filename);
        console.log(__dirname);

        function Hello(){
               console.log( "Hello, World!");
            }

        timer = setTimeout(Hello, 5000);
        clearTimeout(timer)

        console.log("Reached End of File");

    running test.js

        sangram@sangram-HP-Laptop-15-bs0xx:~/workspace/node/global$ node test.js
        /home/sangram/workspace/node/global/test.js
        /home/sangram/workspace/node/global
        Reached End of File

    we can see "Hello World!" is not printed on console as settimeout timer is cleared in.

e) setInterval:global function used to run callback cb repeatedly after at least ms milliseconds.timer cannot span more than 24.8 days.
   
    inside test.js
        console.log(__filename);
        console.log(__dirname);

        function Hello(){
               console.log( "Hello, World!");
            }

        //timer = setTimeout(Hello, 1);
        //clearTimeout(timer)

        setInterval(Hello,2000)
        console.log("Reached End of File");

    running test.js
        sangram@sangram-HP-Laptop-15-bs0xx:~/workspace/node/global$ node test.js
        /home/sangram/workspace/node/global/test.js
        /home/sangram/workspace/node/global
        Reached End of File
        Hello, World!
        Hello, World!
        Hello, World!
        Hello, World!
        ^C
f) clearInterval: global function used to stop a timer that was previously created with setInterval()

    inside test.js
        console.log(__filename);
        console.log(__dirname);

        function Hello(){
               console.log( "Hello, World!");
            }

        //timer = setTimeout(Hello, 1);
        //clearTimeout(timer)


        timer2 = setInterval(Hello,2000)
        clearInterval(timer2)

        console.log("Reached End of File");

    running test.js
        sangram@sangram-HP-Laptop-15-bs0xx:~/workspace/node/global$ node test.js
        /home/sangram/workspace/node/global/test.js
        /home/sangram/workspace/node/global
        Reached End of File

    no "Hello World!" is printed on console.
 
Global Objects:
    Console, Process & Buffer are commonly used global objects in node.js.Console used to print message on stdout and stderr.Process used to get information on current process.
    Console has three methods console.log(),console.error() & console.warn() for printing output.

Global modules:

    a) OS:
        Provides basic operating-system related utility functions.
     b) Path:
        Provides utilities for handling and transforming file paths.
    c) Net :
        Provides both servers and clients as streams. Acts as a network wrapper.
     d) DNS :
        Provides functions to do actual DNS lookup as well as to use underlying operating system name resolution functionalities.
    e)Domain:
        Provides ways to handle multiple different I/O operations as a single group.

Exploring redis commands - part 2

Redis Lists are simply lists of strings, sorted by insertion order. You can add elements in Redis lists in the head or the tail of the list.
Max length of list is (2^32 - 1).

    127.0.0.1:6379> auth sangram
    OK

    LPUSH creates list where last pushed element is at index 0.

        127.0.0.1:6379> LPUSH subjects english
        (integer) 1
        127.0.0.1:6379> LPUSH subjects marathi
        (integer) 2
        127.0.0.1:6379> LPUSH subjects hindi
        (integer) 3
        127.0.0.1:6379> LPUSH subjects history
        (integer) 4
        127.0.0.1:6379> LPUSH subjects geography
        (integer) 5
        127.0.0.1:6379> LPUSH subjects economics
        (integer) 6
        127.0.0.1:6379> LPUSH subjects maths
        (integer) 7
        127.0.0.1:6379> LPUSH subjects science
        (integer) 8
        127.0.0.1:6379> LLEN subjects
        (integer) 8


    LINDEX get element at specified index in list.

        127.0.0.1:6379> LINDEX subjects 0
        "science"
        127.0.0.1:6379> LINDEX subjects 1
        "maths"
        127.0.0.1:6379> LINDEX subjects 3
        "geography"

    BLPOP command removes the first element in a list it returns the first element, if available, or blocks the client for specific time to execute any command.
        127.0.0.1:6379> BLPOP subjects 100
        1) "subjects"
        2) "science"
        127.0.0.1:6379> LLEN subjects
        (integer) 7

    BRPOP removes element from bottom of list.

        127.0.0.1:6379> BRPOP subjects 100
        1) "subjects"
        2) "english"
        127.0.0.1:6379> LLEN subjects
        (integer) 6

    LRANGE prints  values in list based on start Index & end Index

        127.0.0.1:6379> LRANGE subjects 0 20
         1) "mathsssds"
         2) "mathss"
         3) "maths"
         4) "maths"
         5) "maths"
         6) "english"
         7) "maths"
         8) "economics"
         9) "geography"
        10) "history"
        11) "hindi"
        12) "marathi"

    LPUSHX insert push at head of list only if list is already defined.Here "subjectss" is not defined to insertion fails at 1st attempts then succeed.
        127.0.0.1:6379> LPUSHX subjectss mathsssds
        (integer) 0
        127.0.0.1:6379> LPUSH subjectss mathsssds
        (integer) 1
        127.0.0.1:6379> LPUSHX subjectss mathsssds
        (integer) 2

        RPUSH -insert at bottom of list
        127.0.0.1:6379> RPUSH subjects geometry
        (integer) 13
        127.0.0.1:6379> LRANGE subjects 0 20
         1) "mathsssds"
         2) "mathss"
         3) "maths"
         4) "maths"
         5) "maths"
         6) "english"
         7) "maths"
         8) "economics"
         9) "geography"
        10) "history"
        11) "hindi"
        12) "marathi"
        13) "geometry"

      below LREM removes 2 occurances "maths" from list starting search from top to bottom.if instead 2 its negative value say -2 them search start from bottom to top,if instead of 2 its 0 then remove     all occurances of search string in list.


        127.0.0.1:6379> LRANGE subjects 0 20
         1) "mathsssds"
         2) "mathss"
         3) "maths"
         4) "maths"
         5) "maths"
         6) "english"
         7) "maths"
         8) "economics"
         9) "geography"
        10) "history"
        11) "hindi"
        12) "marathi"
        13) "geometry"
        127.0.0.1:6379> LREM subjects 2 maths
        (integer) 2
        127.0.0.1:6379> LRANGE subjects 0 20
         1) "mathsssds"
         2) "mathss"
         3) "maths"
         4) "english"
         5) "maths"
         6) "economics"
         7) "geography"
         8) "history"
         9) "hindi"
        10) "marathi"
        11) "geometry"

    RPUSHX command inserts the value at the bottom of the list  only if the list already exists

        127.0.0.1:6379> RPUSHX s math
        (integer) 0
        127.0.0.1:6379> RPUSHX subject math
        (integer) 0
        127.0.0.1:6379> RPUSHX subjects math
        (integer) 8

       RPOP removes and return last element from bottom in list

    127.0.0.1:6379> LRANGE subjects 0 20
    1) "english"
    2) "economics"
    3) "geography"
    4) "history"
    5) "hindi"
    6) "marathi"
    7) "geometry"
    8) "math"

    127.0.0.1:6379> RPOP subjects
    "math"

    127.0.0.1:6379> LRANGE subjects 0 20
    1) "english"
    2) "economics"
    3) "geography"
    4) "history"
    5) "hindi"
    6) "marathi"
    7) "geometry"

    LPOP removes and returns the first element in top list.

        127.0.0.1:6379> LRANGE subjects 0 20
        1) "english"
        2) "economics"
        3) "geography"
        4) "history"
        5) "hindi"
        6) "marathi"
        7) "geometry"
        127.0.0.1:6379> LPOP subjects
        "english"

    RPOPLPUSH -removes element from bottom of list and insert into new list


    127.0.0.1:6379> LRANGE subjects 0 20
    1) "economics"
    2) "geography"
    3) "history"
    4) "hindi"
    5) "marathi"
    6) "geometry"

    127.0.0.1:6379> RPOPLPUSH subjects s
    "geometry"

    127.0.0.1:6379> LRANGE subjects 0 20
    1) "economics"
    2) "geography"
    3) "history"
    4) "hindi"
    5) "marathi

    127.0.0.1:6379> LRANGE s 0 20
    1) "geometry"

Saturday, September 22, 2018

Exploring redis commands - part 1

The first thing to do in order to check if Redis is working properly is sending a PING command using redis-cli:

    127.0.0.1:6379> ping
    PONG

saving key & retreving saved value

    127.0.0.1:6379> set mykey myvalue
    OK

    127.0.0.1:6379> get mykey
    "myvalue"
    127.0.0.1:6379>

setting password
    open "/etc/redis/redis.conf" and look for "requirepass" commented line,uncomment it set password as
    requirepass sangram

    then we need to restart service

         sudo service redis-server restart .now we need to open redis-cli again
on redis-cli we will check password is enforced or not,lets try to set some random key value as follows

    127.0.0.1:6379> set mykey test
    (error) NOAUTH Authentication required.

Now we will keyin password as follows
    127.0.0.1:6379> auth sangram
    OK
after getting authenticated we are able to save key

    127.0.0.1:6379> set mykey test
    OK
Getting config value
    127.0.0.1:6379> config get requirepass
    1) "requirepass"
    2) "sangram"

Overrride key
    127.0.0.1:6379> set mykey test2
    OK
    127.0.0.1:6379> get mykey
    "test2"
Deleteing key:
    127.0.0.1:6379> DEL mykey
    (integer) 1
List keys by pattern:
    127.0.0.1:6379> set mykey1 test2
    OK
    127.0.0.1:6379> set mykey2 test2
    OK
    127.0.0.1:6379> KEYS my*
    1) "mykey2"
    2) "mykey"
    3) "mykey1

List All Keys:
    127.0.0.1:6379> KEYS *
    1) "mykey2"
    2) "mykey"
    3) "mykey1"

Expiry:
    Redis Expire command is used to set the expiry of a key. After the expiry time, the key will not be available in Redis.It returns 1, if timeout is set for the key else 0.

    127.0.0.1:6379>  EXPIRE mykey 10
    (integer) 1
     unit of expiry time is in seconds

    checking if key expired
    127.0.0.1:6379> KEYS *
    1) "mykey1"
    2) "mykey2"
    3) "\xe2\x80\x9ca-test\xe2\x80\x9d"
    4) "a-test"

     no occurance of mykey found.

     setting key in milli seconds

    127.0.0.1:6379> set mykey3 test3 PX 5000
    OK


we can also set expiry at the time of adding key

    127.0.0.1:6379> set mykey3 test3 EX 10
    OK

Check if key exist:returns 1 if key exist else 0.
    127.0.0.1:6379> EXISTS mykey3
    (integer) 0

    127.0.0.1:6379> EXISTS mykey1
    (integer) 1

Store Javascript objects in Redis

    127.0.0.1:6379> HSET "a-test" "name.first" "Kyle"
    (integer) 1
    127.0.0.1:6379> HSET "a-test" "name.family" "Davis"
    (integer) 1
    127.0.0.1:6379> HSET "a-test" "address" "123 Main Street"
    (integer) 1

    Get value for saved key:

        127.0.0.1:6379> HGET "a-test" "name.family"
        "Davis"
        127.0.0.1:6379> HGET "a-test" "address"
        "123 Main Street"

         Get value for saved keys:
        127.0.0.1:6379> HMGET "a-test" "name.first" "address"
        1) "Kyle"
        2) "123 Main Street"


     this is same as saving below json in javascript world

    var aTest = {
        "name.first" : ‘Kyle’,
        "name.family" : ‘Davis’,
        "address" : ‘123 Main Street’
      }

    Storing multiple key at in one go:

        127.0.0.1:6379> HMSET adrees city "mumbai" zip "400074"
        OK
        127.0.0.1:6379> HGET adrees city
        "mumbai"

    add key only if key does not exist do not override existing key value

        127.0.0.1:6379> HSETNX adrees city "pune"
        (integer) 0
        127.0.0.1:6379> HSETNX adrees state "maharshtra"
        (integer) 1

    confirming insertion:
        127.0.0.1:6379> HGETALL adrees
        1) "city"
        2) "mumbai"
        3) "zip"
        4) "400074"
        5) "state"
        6) "maharshtra"

       removing key:

        127.0.0.1:6379> HDEL "a-test" "name.family"
        (integer) 1

       view complete hash:

        127.0.0.1:6379> HGETALL "a-test"
        1) "name.first"
        2) "Kyle"
        3) "address"
        4) "123 Main Street"

    list all keys only

        127.0.0.1:6379> HKEYS "a-test"
        1) "name.first"
        2) "address"

    list all values:
        127.0.0.1:6379> HVALS a-test
        1) "Kyle"
        2) "123 Main Street"

    total keys:
        127.0.0.1:6379> HLEN "a-test"
        (integer) 2

    check key exist in hash:
        127.0.0.1:6379> HEXISTS "a-test"  address
        (integer) 1
        127.0.0.1:6379> HEXISTS "a-test"  addresss
        (integer) 0

  
Database:
    In Redis the number of Redis databases is fixed, and set in the configuration file. By default, you have 16 databases. Each database is identified by a number (not a name).

    You can use the following command to know the number of databases:

    127.0.0.1:6379> CONFIG GET databases
    1) "databases"
    2) "16"

       selecting database of specific number

        127.0.0.1:6379> select 1
        OK
        127.0.0.1:6379[1]> set mykey3 test3
        OK
        127.0.0.1:6379[1]> KEYS *
        1) "mykey3"

      on redis-cli switching between databases the key persist.


You can use the following command to list the databases for which some keys are defined:

    127.0.0.1:6379> INFO keyspace
    # Keyspace
    db0:keys=4,expires=0,avg_ttl=0

To get redis backup dir
    127.0.0.1:6379> CONFIG get dir
    1) "dir"
    2) "/var/lib/redis"

Redis SAVE command is used to create a backup of the current Redis database.

    127.0.0.1:6379> SAVE
    OK

    This command will create a dump.rdb file in your Redis directory.

    root@sangram-HP-Laptop-15-bs0xx:/home/sangram/workspace/node/hoisting# ls -lth /var/lib/redis/dump.rdb
    -rw-rw---- 1 redis redis 358 Sep 22 20:24 /var/lib/redis/dump.rdb

       Notice time file has been created.


    BGSAVE command will start the backup process and run this in the background.

    127.0.0.1:6379> BGSAVE
    Background saving started

To restore Redis data, move Redis backup file (dump.rdb) into your Redis backup directory and start the server.

Object.assign in javascipt

    
    Object.assign is used for merging object & cloning purpose.

    Merging Objects in JavaScript


        var o1 = { a: 1 };
        var o2 = { b: 2,a:5 };
        var o3 = { c: 3 };

       var obj = Object.assign(o1, o2, o3);

        console.log(obj); // { a: 5, b: 2, c: 3 }
        console.log(o1);  // { a: 5, b: 2, c: 3 }, target object itself is changed.
        console.log(o2); // {b: 2,a:5 }
        console.log(o3); // { c: 3 }

    Here we are merging o1,o2,o3 object during merge o1 also get merged object value along with returned object "obj". 'a' happens to be in o1 & o2 so in merged object a get value from last object  with a defined in it based on sequence in which they comes in Object.assign.

        Copying Object
              Though object.assign copies object deep clone is not happening.

        var obj2 = Object.assign({ p: 67 }, { q: 09 }, { r: 34 });
        console.log(obj2);

        let obj3 = {person: 'Thor Odinson',adr:{city:"mumbai"}};
        let clone = Object.assign({}, obj3);

        obj3.person ="test"
        obj3.adr.city="kolkota"

        console.log(clone);
        console.log(obj3);


         obj3 adr-->city in copied to "clone" by reference unlike key "person".so deep coping is not happening ,change in source adr-->city will modify in cloned object also.

        Deep Clone:
        let obj4 = {person: 'Thor Odinson',adr:{city:"mumbai"}};
        let deep_clone = JSON.parse(JSON.stringify(obj4))

        obj4.adr.city="pune"
        console.log(deep_clone);
        console.log(obj4);


    Deep clone is possible using JSON.parse(JSON.stringify()) call on object.

 Shallow Copy Example:

var employeeDetailsOriginal = {  name: 'Manjula', age: 25, Profession: 'Software Engineer' };
var employeeDetailsDuplicate = employeeDetailsOriginal; //Shallow copy!
employeeDetailsDuplicate.name = 'NameChanged';

console.log(employeeDetailsOriginal);

console.log(employeeDetailsDuplicate);

Output:
{ name: 'NameChanged', age: 25, Profession: 'Software Engineer' }
{ name: 'NameChanged', age: 25, Profession: 'Software Engineer' }


     Ellipses in Javascript:


           var obj33 =[{a:4,b:7},{p:6,q:5}]
           var obj5 = [... obj33];
           obj33[0].a =44
           console.log(obj5);
           console.log(obj33);


     object array copied using ellipses syntax also not deep clone.

   Copying property by looping:

    var person = {
            name: 'John',
            age: 28,
            adr:{state:"maha"}
    };

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

    newPerson.adr.state="karnataka"
    newPerson.age = 30
    console.log(newPerson === person)
    console.log(person)
 
   copying property by looping in object also do not deep clone.

Friday, September 21, 2018

Quering Mongo


Example collection "maxdemo" is as follows:
{
"_id" : ObjectId("5ba49f63a3b0f1fce83f3f3f"),
"name" : "sangram",
"marks" : 76.0
}
{
"_id" : ObjectId("5ba49f73a3b0f1fce83f3f40"),
"name" : "sagar",
"marks" : 77.0
}
{
"_id" : ObjectId("5ba49f7da3b0f1fce83f3f41"),
"name" : "sachin",
"marks" : 85.0
}
{
"_id" : ObjectId("5ba49f87a3b0f1fce83f3f42"),
"name" : "swapnil",
"marks" : 80.0
}
{
"_id" : ObjectId("5ba49f90a3b0f1fce83f3f43"),
"name" : "saurabh",
"marks" : 90.0
}
{
"_id" : ObjectId("5ba49fa0a3b0f1fce83f3f44"),
"name" : "shashank",
"marks" : 79.0
}
{
"_id" : ObjectId("5ba49fbba3b0f1fce83f3f45"),
"name" : "sunil",
"marks" : 84.0
}
{
"_id" : ObjectId("5ba49fcaa3b0f1fce83f3f46"),
"name" : "sujay",
"marks" : 64.0
}
{
"_id" : ObjectId("5ba49fe4a3b0f1fce83f3f47"),
"name" : "subodh",
"marks" : 74.0
}
{
"_id" : ObjectId("5ba49ff6a3b0f1fce83f3f48"),
"name" : "sunit",
"marks" : 60.0
}




Finding 3rd max of marks

db.maxdemo.find({}).sort({"marks":-1}).skip(2).limit(1)

Finding nth max of marks
db.maxdemo.find({}).sort({"marks":-1}).skip(n-1).limit(1)


Updating our collection to below using

db.maxdemo.update({"name" : "vineet"},{$set: { "subject": "maths" }})

by changing subject & name field values.

{
"_id" : ObjectId("5ba49f63a3b0f1fce83f3f3f"),
"name" : "sangram",
"marks" : 76.0,
"subject" : "english"
}
{
"_id" : ObjectId("5ba49f73a3b0f1fce83f3f40"),
"name" : "sagar",
"marks" : 77.0,
"subject" : "marathi"
}
{
"_id" : ObjectId("5ba49f7da3b0f1fce83f3f41"),
"name" : "sachin",
"marks" : 85.0,
"subject" : "geography"
}
{
"_id" : ObjectId("5ba49f87a3b0f1fce83f3f42"),
"name" : "swapnil",
"marks" : 80.0,
"subject" : "geography"
}
{
"_id" : ObjectId("5ba49f90a3b0f1fce83f3f43"),
"name" : "saurabh",
"marks" : 90.0,
"subject" : "maths"
}
{
"_id" : ObjectId("5ba49fa0a3b0f1fce83f3f44"),
"name" : "shashank",
"marks" : 79.0,
"subject" : "maths"
}
{
"_id" : ObjectId("5ba49fbba3b0f1fce83f3f45"),
"name" : "sunil",
"marks" : 84.0,
"subject" : "geography"
}
{
"_id" : ObjectId("5ba49fcaa3b0f1fce83f3f46"),
"name" : "sujay",
"marks" : 64.0,
"subject" : "marathi"
}
{
"_id" : ObjectId("5ba49fe4a3b0f1fce83f3f47"),
"name" : "subodh",
"marks" : 74.0,
"subject" : "english"
}
{
"_id" : ObjectId("5ba49ff6a3b0f1fce83f3f48"),
"name" : "sunit",
"marks" : 60.0,
"subject" : "english"
}
{
"_id" : ObjectId("5ba4a1fdffaf9599885ab184"),
"name" : "vivek",
"marks" : 85.0,
"subject" : "marathi"
}
{
"_id" : ObjectId("5ba4a205ffaf9599885ab185"),
"name" : "vijay",
"marks" : 85.0
}
{
"_id" : ObjectId("5ba4a20affaf9599885ab186"),
"name" : "vineet",
"marks" : 85.0,
"subject" : "maths"
}

Now lets play with this collection.

for sql query
select subject,max(marks) from maxdemo_table group by subject

equivalent mongo query is

db.maxdemo.aggregate([
{$group : {_id : "$subject", maximum_marks : {$max : "$marks"}}}
])

for sql query
select max(marks) from maxdemo_table
equivalent mongo query is

db.maxdemo.aggregate([
{$group : {_id : null, maximum_marks : {$max : "$marks"}}}

for sql query
select subject,max(marks) from maxdemo_table group by subject having subject ="maths"
])
equivalent mongo query is

db.maxdemo.aggregate([
{$group : {_id : "$subject", maximum_marks : {$max : "$marks"}}},
{$match: { _id : { $eq: "maths"} } },
])
for sql query
select subject,max(marks) from maxdemo_table group by subject having max(marks) = 85
equivalent mongo query is

db.maxdemo.aggregate([
{$group : {_id : "$subject", maximum_marks : {$max : "$marks"}}},
{$match: { maximum_marks : { $eq: 85} } },
])
Getting max value and all records on which max value calculated

db.maxdemo.aggregate([
{
$group : {
_id : "$subject",
maximum_marks : {$max : "$marks"},
student: {$push: "$$ROOT"}
}
}
])

Result:
{
"_id" : "geography",
"maximum_marks" : 85.0,
"student" : [
{
"_id" : ObjectId("5ba49f7da3b0f1fce83f3f41"),
"name" : "sachin",
"marks" : 85.0,
"subject" : "geography"
},
{
"_id" : ObjectId("5ba49f87a3b0f1fce83f3f42"),
"name" : "swapnil",
"marks" : 80.0,
"subject" : "geography"
},
{
"_id" : ObjectId("5ba49fbba3b0f1fce83f3f45"),
"name" : "sunil",
"marks" : 84.0,
"subject" : "geography"
}
]
}
{
"_id" : "maths",
"maximum_marks" : 90.0,
"student" : [
{
"_id" : ObjectId("5ba49f90a3b0f1fce83f3f43"),
"name" : "saurabh",
"marks" : 90.0,
"subject" : "maths"
},
{
"_id" : ObjectId("5ba49fa0a3b0f1fce83f3f44"),
"name" : "shashank",
"marks" : 79.0,
"subject" : "maths"
},
{
"_id" : ObjectId("5ba4a20affaf9599885ab186"),
"name" : "vineet",
"marks" : 85.0,
"subject" : "maths"
}
]
}
{
"_id" : "marathi",
"maximum_marks" : 85.0,
"student" : [
{
"_id" : ObjectId("5ba49f73a3b0f1fce83f3f40"),
"name" : "sagar",
"marks" : 77.0,
"subject" : "marathi"
},
{
"_id" : ObjectId("5ba49fcaa3b0f1fce83f3f46"),
"name" : "sujay",
"marks" : 64.0,
"subject" : "marathi"
},
{
"_id" : ObjectId("5ba4a1fdffaf9599885ab184"),
"name" : "vivek",
"marks" : 85.0,
"subject" : "marathi"
},
{
"_id" : ObjectId("5ba4a205ffaf9599885ab185"),
"name" : "vijay",
"subject" : "marathi",
"marks" : 85.0
}
]
}
{
"_id" : "english",
"maximum_marks" : 76.0,
"student" : [
{
"_id" : ObjectId("5ba49f63a3b0f1fce83f3f3f"),
"name" : "sangram",
"marks" : 76.0,
"subject" : "english"
},
{
"_id" : ObjectId("5ba49fe4a3b0f1fce83f3f47"),
"name" : "subodh",
"marks" : 74.0,
"subject" : "english"
},
{
"_id" : ObjectId("5ba49ff6a3b0f1fce83f3f48"),
"name" : "sunit",
"marks" : 60.0,
"subject" : "english"
}
]
}

Saving result into new collection

var temp = db.maxdemo.aggregate([
{
$group :
{
_id : "$subject",
maximum_marks : {$max : "$marks"},
student: {$push: "$$ROOT"}
}
},
{
$out : "hc_hosting_stat"
}
])

Getting record by comparison of two fields

just for illustration purpose update a record as follows by adding new field beside maximum marks called marks
{
"_id" : "geography",
"maximum_marks" : 85.0,
"marks" : 85.0,
"student" : [
{
"_id" : ObjectId("5ba49f7da3b0f1fce83f3f41"),
"name" : "sachin",
"marks" : 85.0,
"subject" : "geography"
},
{
"_id" : ObjectId("5ba49f87a3b0f1fce83f3f42"),
"name" : "swapnil",
"marks" : 80.0,
"subject" : "geography"
},
{
"_id" : ObjectId("5ba49fbba3b0f1fce83f3f45"),
"name" : "sunil",
"marks" : 84.0,
"subject" : "geography"
}
]
}
and below
{
"_id" : "maths",
"maximum_marks" : 90.0,
"marks" : 89.0,
"student" : [
{
"_id" : ObjectId("5ba49f90a3b0f1fce83f3f43"),
"name" : "saurabh",
"marks" : 90.0,
"subject" : "maths"
},
{
"_id" : ObjectId("5ba49fa0a3b0f1fce83f3f44"),
"name" : "shashank",
"marks" : 79.0,
"subject" : "maths"
},
{
"_id" : ObjectId("5ba4a20affaf9599885ab186"),
"name" : "vineet",
"marks" : 85.0,
"subject" : "maths"
}
]
}

Now lets issue a mongo query
db.hc_hosting_stat.find({$where: function() { return this.maximum_marks == this.marks } } );

Result:
{
"_id" : "geography",
"maximum_marks" : 85.0,
"marks" : 85.0,
"student" : [
{
"_id" : ObjectId("5ba49f7da3b0f1fce83f3f41"),
"name" : "sachin",
"marks" : 85.0,
"subject" : "geography"
},
{
"_id" : ObjectId("5ba49f87a3b0f1fce83f3f42"),
"name" : "swapnil",
"marks" : 80.0,
"subject" : "geography"
},
{
"_id" : ObjectId("5ba49fbba3b0f1fce83f3f45"),
"name" : "sunil",
"marks" : 84.0,
"subject" : "geography"
}
]
}

we are getting all records where maximum_marks matches marks.


For collection "hc_hosting_stat"

{
"_id" : "geography",
"maximum_marks" : 85.0,
"marks" : 85.0,
"student" : [
{
"_id" : ObjectId("5ba49f7da3b0f1fce83f3f41"),
"name" : "sachin",
"marks" : 85.0,
"subject" : "geography"
},
{
"_id" : ObjectId("5ba49f87a3b0f1fce83f3f42"),
"name" : "swapnil",
"marks" : 80.0,
"subject" : "geography"
},
{
"_id" : ObjectId("5ba49fbba3b0f1fce83f3f45"),
"name" : "sunil",
"marks" : 84.0,
"subject" : "geography"
}
]
}
{
"_id" : "maths",
"maximum_marks" : 90.0,
"marks" : 89.0,
"student" : [
{
"_id" : ObjectId("5ba49f90a3b0f1fce83f3f43"),
"name" : "saurabh",
"marks" : 90.0,
"subject" : "maths"
},
{
"_id" : ObjectId("5ba49fa0a3b0f1fce83f3f44"),
"name" : "shashank",
"marks" : 79.0,
"subject" : "maths"
},
{
"_id" : ObjectId("5ba4a20affaf9599885ab186"),
"name" : "vineet",
"marks" : 85.0,
"subject" : "maths"
}
]
}
{
"_id" : "marathi",
"maximum_marks" : 85.0,
"student" : [
{
"_id" : ObjectId("5ba49f73a3b0f1fce83f3f40"),
"name" : "sagar",
"marks" : 77.0,
"subject" : "marathi"
},
{
"_id" : ObjectId("5ba49fcaa3b0f1fce83f3f46"),
"name" : "sujay",
"marks" : 64.0,
"subject" : "marathi"
},
{
"_id" : ObjectId("5ba4a1fdffaf9599885ab184"),
"name" : "vivek",
"marks" : 85.0,
"subject" : "marathi"
},
{
"_id" : ObjectId("5ba4a205ffaf9599885ab185"),
"name" : "vijay",
"subject" : "marathi",
"marks" : 85.0
}
]
}
{
"_id" : "english",
"maximum_marks" : 76.0,
"student" : [
{
"_id" : ObjectId("5ba49f63a3b0f1fce83f3f3f"),
"name" : "sangram",
"marks" : 76.0,
"subject" : "english"
},
{
"_id" : ObjectId("5ba49fe4a3b0f1fce83f3f47"),
"name" : "subodh",
"marks" : 74.0,
"subject" : "english"
},
{
"_id" : ObjectId("5ba49ff6a3b0f1fce83f3f48"),
"name" : "sunit",
"marks" : 60.0,
"subject" : "english"
}
]
}





Getting subject topper and topped marks

db.hc_hosting_stat.find({}).forEach(function(item)
{
var new_item=[];
for(var i=0;i < item.student.length;i++){
if(item.student[i].marks == item.maximum_marks){
new_item.push(item.student[i])
}
}
db.result.insert(new_item)
})

New result collection is as below
{
"_id" : ObjectId("5ba49f7da3b0f1fce83f3f41"),
"name" : "sachin",
"marks" : 85.0,
"subject" : "geography"
}
{
"_id" : ObjectId("5ba49f90a3b0f1fce83f3f43"),
"name" : "saurabh",
"marks" : 90.0,
"subject" : "maths"
}
{
"_id" : ObjectId("5ba4a1fdffaf9599885ab184"),
"name" : "vivek",
"marks" : 85.0,
"subject" : "marathi"
}
{
"_id" : ObjectId("5ba4a205ffaf9599885ab185"),
"name" : "vijay",
"subject" : "marathi",
"marks" : 85.0
}
{
"_id" : ObjectId("5ba49f63a3b0f1fce83f3f3f"),
"name" : "sangram",
"marks" : 76.0,
"subject" : "english"
}

or

db.hc_hosting_stat.aggregate([
             {
                $project: {
                    maximum_marks: 1,
                    'topper': {
                        $filter: {
                            input: '$student',
                            as: 'item',
                            cond: {
                                $eq: ['$$item.marks', '$maximum_marks']
                            }
                        }
                    }
                }
            }
        ])

Result:

{
    "_id" : "geography",
    "maximum_marks" : 85.0,
    "topper" : [
        {
            "_id" : ObjectId("5ba49f7da3b0f1fce83f3f41"),
            "name" : "sachin",
            "marks" : 85.0,
            "subject" : "geography"
        }
    ]
}
{
    "_id" : "maths",
    "maximum_marks" : 90.0,
    "topper" : [
        {
            "_id" : ObjectId("5ba49f90a3b0f1fce83f3f43"),
            "name" : "saurabh",
            "marks" : 90.0,
            "subject" : "maths"
        }
    ]
}
{
    "_id" : "marathi",
    "maximum_marks" : 85.0,
    "topper" : [
        {
            "_id" : ObjectId("5ba4a1fdffaf9599885ab184"),
            "name" : "vivek",
            "marks" : 85.0,
            "subject" : "marathi"
        },
        {
            "_id" : ObjectId("5ba4a205ffaf9599885ab185"),
            "name" : "vijay",
            "subject" : "marathi",
            "marks" : 85.0
        }
    ]
}
{
    "_id" : "english",
    "maximum_marks" : 76.0,
    "topper" : [
        {
            "_id" : ObjectId("5ba49f63a3b0f1fce83f3f3f"),
            "name" : "sangram",
            "marks" : 76.0,
            "subject" : "english"
        }
    ]
}

combining two steps into one:

This query list all subject toppers keeping in concern that many student getting top score in a subject.e.g.vivek & vineet both score top in Marathi.

 db.maxdemo.aggregate([
{
    $group : {
        _id : "$subject",
        topscore : {$max : "$marks"},
        student: {$push: "$$ROOT"}
    }      
},
{
  $project:
  {
        topscore: 1,
        _id:0,
        'subject': '$_id',
        'topper': {
                        $filter: {
                            input: '$student',
                            as: 'item',
                            cond: {
                                $eq: ['$$item.marks', '$topscore']
                            }
                        }
                    }
  }
}
])

Result:

{
    "topscore" : 85.0,
    "subject" : "geography",
    "topper" : [
        {
            "_id" : ObjectId("5ba49f7da3b0f1fce83f3f41"),
            "name" : "sachin",
            "marks" : 85.0,
            "subject" : "geography"
        }
    ]
}
{
    "topscore" : 90.0,
    "subject" : "maths",
    "topper" : [
        {
            "_id" : ObjectId("5ba49f90a3b0f1fce83f3f43"),
            "name" : "saurabh",
            "marks" : 90.0,
            "subject" : "maths"
        }
    ]
}
{
    "topscore" : 85.0,
    "subject" : "marathi",
    "topper" : [
        {
            "_id" : ObjectId("5ba4a1fdffaf9599885ab184"),
            "name" : "vivek",
            "marks" : 85.0,
            "subject" : "marathi"
        },
        {
            "_id" : ObjectId("5ba4a205ffaf9599885ab185"),
            "name" : "vijay",
            "subject" : "marathi",
            "marks" : 85.0
        }
    ]
}
{
    "topscore" : 76.0,
    "subject" : "english",
    "topper" : [
        {
            "_id" : ObjectId("5ba49f63a3b0f1fce83f3f3f"),
            "name" : "sangram",
            "marks" : 76.0,
            "subject" : "english"
        }
    ]
}