Filtering the inputs in Node.js - node.js

Here, I am fetching a data from the user. The first line contains an integer, denoting the number of entries in the phone book.
Each of the subsequent lines describes an entry in the form of space-separated values on a single line. The first value is a friend's name, and the second value is a digit phone number.
For example:
2
sam 99912222
tom 11122222
So, while processing this input, I am taking the number of entries from the user and assigning it to variable noOfIterations. For the subsequent entries, I am assigning it to a list of objects wherein the format will be : for eg. [{ sam: '99912222' },{ tom: '11122222' }].
But the problem is I get [ 'sam 99912222', 'tom 11122222' ] instead while consoling the map variable. Why do I get this?
function processData(input) {
var noOfIterations = 0;
var map = input.split('\n').filter(function (string, index){
if(index===0){
noOfIterations = parseInt(string);
}
else{
var splitStrings = string.trim().split(' ');
var obj = {};
obj[splitStrings[0]] = splitStrings[1];
console.log(obj);
return obj;
}
});
console.log(map);
}
process.stdin.resume();
process.stdin.setEncoding("ascii");
_input = "";
process.stdin.on("data", function (input) {
_input += input;
});
process.stdin.on("end", function () {
processData(_input);
});

You need to use map instead of filter to transform the input data.
function processPhoneBook(input) {
var result = input.split('\n')
.filter(function(line, index) { return index > 0 })
.map(function(line) {
var splitLine = line.trim().split(' ');
return {[splitLine[0]]: splitLine[1]};
});
console.log(result);
}
Example:
processPhoneBook("3\nana 1\npep 2") outputs [ { ana: '1' }, { pep: '2' } ]
I've removed noOfIterations var since you weren't using it. If you need to use it for further processing, you can filter the result after the mapping phase:
function processPhoneBook(input) {
var noOfIterations = 0;
var result = input.split('\n')
.map(function(line, index) {
if (index === 0) {
noOfIterations = parseInt(line);
return null;
}
var splitLine = line.trim().split(' ');
return {[splitLine[0]]: splitLine[1]};
})
.filter(function(line) { return line != null })
console.log(result);
}

Related

I would like to ask why nodejs variables are affected even though they are not global variables?

// my router.js
var express = require('express');
...
...
var async = require('async');
var sboard = require('../lib/sboard.js');
router.get('/shop/list/',async function(req,res,next){
//var url_parse = url.parse(cfg.url_full);
//cfg.url_query = url_parse.query;;
var data = await sboard.get_list(req);
var main_arr = templateSboardList.MAIN(data);
var main_body = main_arr['body'];
var main_js = main_arr['js'];
var main_title = main_arr['title'];
commonTemplate.PAGEBODY(req,res,next,main_title,main_body,main_js,db,function(result){
res.send(result);
});
// my /lib/sboard.js
// return result ['page=1&btype=mk', { page: '1', btype: 'mk' }]
get_qstr:function(req){
var qstr = [];
var qstr_obj = {};
if(typeof req.query.page !== 'undefined'){
qstr.push(['page='+req.query.page]);
qstr_obj['page'] = req.query.page;
}
if(typeof req.query.btype !== 'undefined'){
qstr.push(['btype='+req.query.btype]);
qstr_obj['btype'] = req.query.btype;
}
if(typeof req.query.btype_sub !== 'undefined'){
qstr.push(['btype_sub='+req.query.btype_sub]);
qstr_obj['btype_sub'] = req.query.btype_sub;
}
if(typeof req.query.search_keyword !== 'undefined'){
qstr.push(['search_keyword='+req.query.search_keyword]);
qstr_obj['search_keyword'] = req.query.search_keyword;
}
return [qstr.join('&'),qstr_obj];
},
get_qstr_filter:function(data,items){
if(data[0].length){
var new_data = data[0].split('&');
data[0] = [];
for(var i in new_data){
var v = new_data[i].split('=');
if(!in_array(v[0],items)){
data[0].push([v[0]+'='+v[1]]);
}
}
data[0] = data[0].join('&');
}
if(Object.keys(data[1]).length){
for(var i in data[1]){
for(var ii in items){
delete(data[1][items[ii]]);
}
}
}
var v = data
return v;
},
get_list:async function(req){
var cfg = {
btype:typeof req.query.btype!=='undefined'?req.query.btype:'mk',
btype_sub:typeof req.query.btype_sub!=='undefined'?req.query.btype_sub:'board',
page_current: typeof req.query.page == 'undefined'?1:parseInt(req.query.page),
page_limit:5,
search_keyword:typeof req.query.search_keyword!=='undefined'?req.query.search_keyword:'',
url_full:req.protocol + '://' + req.get('host') + req.originalUrl,
url_qstr:this.get_qstr(req)
}
// result log [ 'page=1&btype=mk', { page: '1', btype: 'mk' } ]
console.log('aaa',cfg.url_qstr);
// result log [ 'btype=mk', { btype: 'mk' } ]
console.log('bbb',this.get_qstr_filter(cfg.url_qstr,['page'])[1]);
// result log [ 'btype=mk', { btype: 'mk' } ]
console.log('ccc',cfg.url_qstr);
}
In the console.log ccc section,
why is the value of cfg set to the return value when calling get_qstr_filter?
the result of my thoughts console.log ccc section
result log [ 'page=1&btype=mk', { page: '1', btype: 'mk' } ]
Shouldn't it have the same value as the console.log aaa section?
Why does the cfg value change in the ccc section
after calling the function?
Why are variables initialized with the function's return value after calling the function? cfg is not a global variable.
Arrays in JS are objects. e.g typeof [] == 'object'
Objects get passed by "reference value". Meaning, when you pass an object (or in this case array) in a function parameter, you are passing a value with a reference to the object, and not a copied value of the object. Any changes to the reference will reflect in all the places it is referenced (e.g. in the cfg object instance).
In your code, this.get_qstr_filter(cfg.url_qstr,['page'])[1]) is passing the reference value to the array, so when data argument is mutated, it is (also) mutating the original (referenced in the cfg object).
Another way to put it: data argument in this case is not a local variable holding a copy of the cfg.url_qstr array, it's a local variable holding a reference to the cfg.url_qstr array.

async.waterfall randomly sorts results

I was writing a nest code, tried using async.waterfall or async.series but I am getting random results every time I refresh. it seems to be because of the queries of the first 2 functions randomly finishing.
first query was sorting to committed_date DESC. but when I add the 2 sub queries. the sort gets distorted.
Step1: Loop landingpages
Step1.1 - fetch details1 repositories
Step1.2 - fetch details2 versions
Step2: build array
db.collection('landingpages').find({is_deleted:{$ne:1}}).sort({committed_date:-1}).limit(10).toArray(function(err, db_results) {
var data_array = [];
var x=1;
if(db_results.length == 0) {
return_data.lps = data_array;
parallel_done();
}else{
async.each(db_results, function (db_results1, cb) {
async.watefall(
[
function(callback) {
//if this is removed or passed as callback(null, ""); the sort is fixed from committed - 1
var data_repo = {};
db.collection('repositories').find({repository_id: repository_id}).toArray(function(err, db_results1) {
if(db_results1.length == 0){
var data_repo = {};
callback(null, data_repo);
}else{
var data_repo = db_results1[0];
callback(null, data_repo);
}
});
},
function(callback) {
//if this is removed or passed as callback(null, ""); the sort is fixed from committed - 1
var data_version = {};
db.collection('versions').find({landingpage_id: landingpage_id}).sort({_id:-1}).limit(1).toArray(function(err, db_results1) {
if(db_results1.length == 0){
var data_version = {};
callback(null, data_version);
}else{
var data_version = db_results1[0];
callback(null, data_version);
}
});
}
],
function (err, data_repo,data_version) {
var document = {
"x": x++,
"landingpage_id": db_results1.landingpage_id,
"repository_id": db_results1.repository_id,
"version_id": data_version.version_id,
"val": db_results1,
"data_repo": data_repo,
"data_version": data_version,
};
data_array.push(document);
if(data_array.length == db_results.length) {
return_data.lps = data_array;
}
}
);
});
}
});

Node.js passing variable to parent function

So i ran into a problem. I don't know how to pass single string to the parental function from a child function and then pass that string as a response to the client side.
This whole thing gets five recent matches from API and then checks for a win or a loss depending on the player name.
Question 1: as i said before i don't know how to pass string from a child function to the parental function and then send it as a response to client side.
Question 2: the output of this should be WWWLW and how i think it should be ordered like that. But every time it outputs in different order like LWWWW WLWWW and so on... it has good arguments but different order and i am missing something here.
code:
var request = require('request');
app.get('/history',getmatches, getwins);
function getmatches(req, res, next){
var match = {};
request({
url: "https://eun1.api.riotgames.com/lol/match/v3/matchlists/by-account/"+ID+"/recent?api_key=" + key,
json: true
}, function (error, res) {
if (!error && res.statusCode === 200) {
for(var i=0; i < 5; i++){ //getting ID's of five last matches
match[i] = res.body.matches[i].gameId;
}
req.somevariable = match;
next();
}
}
);
};
function getwins(req, res, callback){
var match = req.somevariable;
var streak = '';
var pending = 0;
for( i = 0; i < 5; i++){ // passing ID's to another api link to get single match data
request({
url: "https://eun1.api.riotgames.com/lol/match/v3/matches/"+match[i]+"?api_key=" + key,
json: true
}, function(req,res, body){
for(var j = 0; j < 10; j++){ //looping through 10 players in a match to find specific one
if(body.participantIdentities[j].player.summonerName == nickname){
if( body.participants[j].stats.win == true){
streak += 'W';
}else{
streak += 'L';
}
}
}
if(pending == 4){
console.log(streak); // need this to pass to parent function
return callback(null, streak); // is this something i need ?
}
pending++
});
}
// res streak string to client.js
};
There is solution to process all results when it done. The result variable have all results use any appropriate key instead of url;
function getwins(req, res, callback){
var match = req.somevariable;
var streak = '';
var pending = 0;
var results = {};
var total = 5;
for( i = 0; i < total; i++){ // passing ID's to another api link to get single match data
var url = "https://eun1.api.riotgames.com/lol/match/v3/matches/"+match[i]+"?api_key=" + key;
request({
url: url,
json: true
}, function(req,res, body){
for(var j = 0; j < 10; j++){ //looping through 10 players in a match to find specific one
if(body.participantIdentities[j].player.summonerName == nickname){
if( body.participants[j].stats.win == true){
streak += 'W';
}else{
streak += 'L';
}
}
}
console.log(streak); // need this to pass to parent function
results[url] = streak;
if( total == Object.keys(results).length ) {
// here all requests are done - do with all result what you need
console.log( results );
}
return callback(null, streak); // is this something i need ?
}
});
}
// res streak string to client.js
};

get name from id inside loop in node js

hello all I am new to node js and mongo db so I am facing a problem which is written above want to match an id from an array and get all the record of matching id , but thats not working i have already tried for loop but that is taking too much time so i am looking for some kind of query by which I pass id and get the matching results i have below function also where i can pass id and get the matching result but i don't know how to call that .
exports.getDistrictFromId = function(req, res, next) {
var distId = req.params.id;
districtslib.getDistricts({_id: utils.toObjectId(distId)}, function(err, district) {
if (err) {
return next(err);
}
req.store.district = district;
next();
});
};
Here is my code
exports.getCompleteTeachersList = function(req, res, next) {
var query = req.store.get('query');
var teacherQuery = {enabled: true};
var searchQuery = '';
if (!_.isUndefined(query)) {
// schoolQuery = {'name':new RegExp(query.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"),'i')};
//{ $text: { $search: "amit hinduja"} }
//teacherQuery = {enabled: true,$or:[{firstName:new RegExp(query.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"),'i')},{lastName:new RegExp(query.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"),'i')}]};
if(query.trim() != '') {
teacherQuery = {enabled: true,$text: { $search: query} };
searchQuery = query;
}
}
teacherslib.getTeachers(teacherQuery, function(err, teachers) {
if (err) {
return next(err);
}
var schools = req.store.get('schools');
for(var i = 0; i < teachers.length; i++) {
teachers[i].schoolName = "";
for(var j = 0; j < schools.length; j++) {
if (teachers[i].schoolId.toString() === schools[j]._id.toString()) {
teachers[i].schoolName = schools[j].name;
teachers[i].distId = "";
var districts = req.store.get('districts');
console.log(schools[j].distId);
// i want to get the array of matching district id `schools[j].distId` from the district array from `var districts = req.store.get('districts');` this line
break;
}
}
}
req.store.set('searchQuery', searchQuery);
req.store.set('teachers', teachers);
//req.store.set('districts', districts);
next();
});
};
Collection structure is like this
1) distid is coming in schools collection
using distid get all the matching record from district
2)district array has countyid and from that county id has to get data from the county collection
Instead of looping inside a loop, i would suggest you look into the $lookup operator of the aggregation framework. Here you can perform the lookup server side.

About terminating a dynamically constructed sequence of promises

I wrote a script in Node that iterates over a large MongoDB collection, returning a certain number of documents at a time.
The collection has this simple format:
{
name: 'One',
data: '...'
},
{
name: 'Two',
data: '...'
},
...
I'm doing this job with the Q library, using a sequence of promises that get run one after the other:
'use strict';
var Q = require('q');
var monk = require('monk');
var CHUNK_SIZE = 100;
var LIMIT = 1000;
var collection = monk('localhost/dictionary').get('entries');
var promiseFactory = function (j) {
return function (result) {
if (undefined !== result) { // if result is undefined, we are at the first or last iteration.
if (result.length) {
for (var k = 0, max = result.length; k < max; k++) {
console.log(result[k].name); // print name
// ... do something with the document here...
}
} else { // no more documents, end of the iteration
return; // implicitely returns undefined
}
}
// returns CHUNK_SIZE documents, starting from the j-th document
return collection.find({}, { limit: CHUNK_SIZE, skip: j, sort: { name: 1 }});
};
};
var funcs = [];
for (var i = CHUNK_SIZE; i <= LIMIT; i += CHUNK_SIZE) {
funcs.push(promiseFactory(i));
}
var loop = Q.fcall(promiseFactory(0));
funcs.forEach(function (f) {
loop = loop.then(f);
});
The script works well and does achieve what it was designed to do.
However, I would like to improve it:
I'm hardcoding the number of documents in the collection (LIMIT). I would like to get rid of this variable and let the script detect when to stop.
I have a feeling that this approach may not be the most memory-efficient one. In my code, funcs.forEach() chains a lot of copies of the same function in one shot (to be exact LIMIT/CHUNK_SIZE copies). Since I'm working on a very large collection, I was wondering if there's a way to chain a new function only if there are still documents left, while running through the collection.
I think I found the solution to both problems. It is just a simple addition in promiseFactory() which I have highlighted below. Adding it here in the hope it is useful to someone:
var promiseFactory = function (j) {
return function (result) {
if (undefined !== result) { // if result is undefined, we are at the first or last iteration.
if (result.length) {
for (var k = 0, max = result.length; k < max; k++) {
console.log(result[k].en + ' - ' + result[k].le);
}
} else { // no more entries, end of the iteration
return; // implicitely returns undefined
}
}
///////////////// CHANGE HERE ////////////////////////
return entries.find({}, { limit: CHUNK_SIZE, skip: j, sort: { en: 1 }}).then(promiseFactory(j + CHUNK_SIZE));
///////////////////// END ////////////////////////////
};
};

Resources