Node.js for loop output only last item from JSON - node.js

The code below only output the last result, I don't get it. I check if the updateDate item contains 2020-05 both items does and I get only the last one. The loop is not looping :)
const briefing = [
{
"updateDate": "2020-05-05T00:00:00.0Z",
},
{
"updateDate": "2020-05-06T00:00:00.0Z",
},
{
"updateDate": "2020-05-13T00:00:00.0Z",
}
];
let date = new Date();
var formattedYearMonth = date.getFullYear() + '-' + ('0' + (date.getMonth()+1)).slice(-2) + '-';
for (var i = 0; i < briefing.length; i++) {
var jsonDate = briefing[i].updateDate;
if (jsonDate.includes(formattedYearMonth)) {
var response = JSON.stringify(briefing[i]);
}
}return response;
}

for (var i = 0; i < briefing.length; i++) {
var jsonDate = briefing[i].updateDate;
if (jsonDate.includes(formattedYearMonth)) {
var response = JSON.stringify(briefing[i]); // <==== THIS IS WHERE YOUR PROBLEM LIES
}
}return response;
The loop is actually looping :). But for every run of the loop, you are resetting the value of response.
--EDITED--
For the response to be an array, you need to modify your code as
let response = [];
for (var i = 0; i < briefing.length; i++) {
var jsonDate = briefing[i].updateDate;
if (jsonDate.includes(formattedYearMonth)) {
response.push(JSON.stringify(briefing[i]));
}
}
return response;

Related

Batch 500 writes into firestore loop from json file

Using some inspiration I got from this thread and reply I tried to get my loop working which is to write into firestore in batches. But somehow I only can only update 1 document even if I can see I iterate through different values from my array. I load data into an array and work from there.
const db = admin.firestore();
const jsonStream = StreamArray.withParser();
let arr = []
jsonStream.on('data', ({ key, value }) => {
arr.push(value);
});
jsonStream.on('end', () => {
var counter = 0;
var commitCounter = 0;
var batches = [];
arr.forEach((a, ind) => {
batches[commitCounter] = db.batch();
if (counter <= 498) {
var thisRef = db.collection('Testing').doc(a.id);
console.log("id")
console.log(a.id);
batches[commitCounter].set(thisRef, { ...a });
counter = counter + 1;
} else {
counter = 0;
commitCounter = commitCounter + 1;
batches[commitCounter] = db.batch();
}
})
for (var i = 0; i < batches.length; i++) {
if(i==0)
{
console.log(batches[0])
}
batches[i].commit().then(function () {
console.count('wrote batch');
});
}
});
const filename = path.join(__dirname, 'mydata.json');
fs.createReadStream(filename).pipe(jsonStream.input);
Following line gets executed on each iteration, which essentially "resets" your batch on each round:
batches[commitCounter] = db.batch();
So at the end each of your batches will only contain one document write.

Problem with findOne() in sequelize node.js

I have a problem with node.js and sequelize findOne(). I want to find new students, that I want to add to the DB (var novi), and the ones that already exist, I just want to update their field (var stari). Everything works as expected, only when I want to return JSON with how many new students I added to the DB, and how many are updated, values of stari and novi, go back to 0, but the counting is good, I checked. I know the problem is with asynchronous call, but I don't know how to fix.
app.post('/student', function(req,res) {
var imeGodine = req.body['godina'];
//POMOĆNE SKRIPTE BitBucket.js i citanjeGodina.js
var broj = 0;
var stari = 0;
var novi = 0;
db.godina.findOne({where:{nazivGod:req.body.godina}}).then(god => {
var studenti = req.body.studenti;
db.student.count().then (ranijeStudenata => {
for(var i = 0; i<studenti.length; i++) {
var ime = studenti[i].imePrezime;
var ind = studenti[i].index;
db.student.findOne({where:{index :studenti[i].index}}).then(stud => {
if (stud == null) {
novi++;
db.student.create({imePrezime:ime, index : ind}).then(noviStudent => {
god.addStudenti(noviStudent);
});
}
else if (stud != null) {
stari++;
god.addStudenti(stud);
}
});
broj++;
}
var brojNovih = broj - ranijeStudenata; //ne koristi se, ali možda hoće
res.set("Content-Type", "application/json");
res.status(200).send(JSON.stringify({message: "Dodano je " + novi + " novih studenata i upisano " + stari + " na godinu " + imeGodine}));
});
});
});
Picture of code
You can use async/await to do counting in a synchronous way.
'use strict';
app.post('/student', async function (req, res) {
var imeGodine = req.body['godina'];
var {studenti} = req.body;
var broj = 0;
var stari = 0;
var novi = 0;
let god = await db.godina.findOne({where: {nazivGod: req.body.godina}});
let ranijeStudenata = await db.student.count(); // ranijeStudenata not used?
for (var i = 0; i < studenti.length; i++) {
var ime = studenti[i].imePrezime;
var ind = studenti[i].index;
let stud = await db.student.findOne({where: {index: studenti[i].index}});
if (stud === null) {
novi++;
let noviStudent = await db.student.create({imePrezime: ime, index: ind});
god.addStudenti(noviStudent);
} else if (stud !== null) {
stari++;
god.addStudenti(stud);
}
broj++;
}
return res.status(200).send({
message: "Dodano je " + novi + " novih studenata i upisano " + stari + " na godinu " + imeGodine
});
});

making node wait for db call to get completed

I just started writing node.js code.
I'm writing a code that extracts data from a pdf file, cleans it up and stores it in a database (using couchdb and accessing that using nano library).
The problem is that the calls are being made asynchronously... so the database get calls (i make some get calls to get a few affiliation files during the clean up) get completed only after the program runs resulting in variables being undefined. is there any way around this?
I've reproduced my code below
const fs = require('fs');
const os = require('os');
var couchDB = require('couch-db').CouchDB;
var pdf_table_extractor = require('pdf-table-extractor');
const filename = "PQ-PRI-0005-1806-01-0000_quoteSlipForLIBVIDGI1.pdf"
var nano = require('nano')('https://couchadmin:difficulttoguessmypassword#dbdev.perilwise.com');
var server = new couchDB('https://db.url.com');
server.auth("admin","admin");
var db = nano.db.use('pwfb');
var temp = [];
//New callView function
async function callView(){
try{
const doc = await view('liabilitymdm','pi');
for (var i =0; i<doc.rows.length;i++){
tmp.push(doc.rows[i]);
};
return doc;
} catch(e){
console.log(e);
};
};
function suc(result){
let ttmp = [];
console.log(result);
var pageTables = result.pageTables;
var firstPageTables = pageTables[0].tables;
ttmp = callView();
//this console log shows Promise { <pending> }
console.log(ttmp)
for (var k = 0; k < firstPageTables.length; k++) {
var temp = firstPageTables[k];
if (temp.length > 0) {
dump.push(temp);
}
}
// console.log(dump);
var insurer = filename.substr(37,8);
read_quote_slip(insurer,dump);
}
var read_quote_slip = (insurer,data) => {
console.log("read_quote_slip correctly entered");
var finOut = {};
if (insurer === "LIBVIDGI"){
finOut.insurer = insurer;
finOut.policyType = data[2][0].replace(/Quotation for/g,"");
finOut.natureOfWork = data[13][3];
let dedpos = indexGetter(data, "Deductible")[0];
finOut.deductible = data[dedpos+1][0];
let cov = indexGetter(data, "Coverage Territory and Jurisdiction")[0];
finOut.coverageTerritory = data[cov+1][0].replace(/Territory/g,"");
finOut.coverageJurisdiction = data[cov+2][0].replace(/Jurisdiction/g,"");
let ext = indexGetter(data,"Extensions")[0];
finOut.coverage = data[ext+1][0].split(/\r?\n/);
let majexc = indexGetter(data,"Major Exclusions")[0];
finOut.exclusions = data[majexc+1][0].split(/\r?\n/);
let prdtl = indexGetter(data,"Description")[0];
let prm = premiumcompute(data,prdtl,dedpos);
finOut.premium = prm;
finCleaned = libvidgi_cleaned(finOut);
// console.log(finCleaned);
}
}
var indexGetter = (words,toFind) => {
var finindex = [];
for (var i = 0; i < words.length; i++){
for (var j = 0; j < words[i].length; j++){
if(words[i][j].indexOf(toFind) >=0 ){
finindex.push(i);
}
}
}
return finindex;
}
var premiumcompute = (data, from, to) => {
let finprem = [];
let numbop = to - from - 2;
let incr = 0;
for (var i = from+2; i < to; i++){
let pr = {};
pr.option = incr+1;
pr.sumInsured = data[i][2].replace(/ /g,"");
pr.premium = data[i][data[i].length - 1].replace(/ /g,"");
finprem.push(pr);
incr +=1;
}
return finprem;
}
var libvidgi_cleaned = (finOut) => {
return finOut;
}
var fal = (result) => {
console.log(result);
console.log("there was an error");
}
var readPDFFile = function(filename){
//Decide which insurer from the filename
// console.log(filename);
console.log(filename.substr(37,8)+"Printed on line 38");
insurer = filename.substr(37,8)
pdf_table_extractor(filename, (result) => {suc(result)} , fal);
}
var libvidgi_data_extract = (data) => {
console.log(data);
let arr = data.pageTables.tables;
for (var i = 0; i <= arr.length; i++ ){
console.log(arr[i]);
}
}
readPDFFile(filename);
This answer assumes you are using Node.js > v7.6
Since db.view accepts a callback, and you wish to wait for it to finish, one solution will be to promisify it - meaning to turn it into a promise which can be awaited. You can use a library like Bluebird or you can even use Node's builtin promisify util. Then you can rewrite callViews:
const {promisify} = require('util');
const view = promisify(db.view);
async function callView() {
try {
const doc = await view('liabilitymdm', 'pi');
// the async operation is now guaranteed to be done
// (if there is an error it will be caught by the catch clause)
for (var i = 0; i < doc.rows.length; i++) {
temp.push(doc.rows[i]);
}
console.log(temp);
} catch (e) {
}
}
If you are not using Node.js > v7.6 (and cannot use async\await you can still utilize promises, by using their then method:
const {promisify} = require('util');
const view = promisify(db.view);
function callView() {
view('liabilitymdm', 'pi')
.then(doc => {
for (var i = 0; i < doc.rows.length; i++) {
temp.push(doc.rows[i]);
}
console.log(temp);
return temp;
})
.then(temp => {
console.log(temp);
})
.catch(e => {});
}
Notice how the first then is returning something which is used in a later then.
To make Node run asynchronously, you can use the keywords async and await.
They work like this:
async function doSomething () {
const formattedData = formatData();
const result = await db.postToDatabase(formattedData);
// the below will not happen until the above line is finished
doSomethingElse(result);
}
It's pretty simple in Node to get functions to execute asynchronously. Just put the async keyword at the beginning of the function definition and then put await in front of anything that you want to block execution until completed.

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
};

How best to format a returned object

I'm currently returning a set of objects from a database as follows:
function returnedData () {
query.find({
success: function(results) {
for (var i = 0; i < results.length; i++) {
var object = results[i];
var title = object.get('Title');
var summary = object.get('Summary');
var html = '<p>' + title + '</p>';
}
}
});
}
This works fine if I output it doing the following:
$('.results').append(html);
However, I would like the returned object returned in such a fashion that I can use underscore.js to insert the data correctly etc
var listOfContacts = [
{
title: title,
summary: summary
},
{
title: title2,
summary: summary2
}
];
Is there any way that the returned data can be formatted in such a way?
Do you mean something more complicated than this?
results.map(object => ({title: object.get('Title'), summary: object.get('Summary')}))
Old-fashioned way:
var result = [];
for (var i = 0; i < results.length; i++) {
var object = results[i];
var Title = object.get('Title');
var Summary = object.get('Summary');
result.push({ title: Title, summary: Summary });
}

Resources