Inserting and deleting rows in excel with node.js cause problems - node.js

I have a node.js file whose function is to insert and delete columns in an excel file,Im working with the 'xslx' module.
Both insert and delete rows have their own function, so when I call one without calling the other, everything works fine, but if I call them at the same time they don't work as they should, the rows are repeated and not added as they should.
This is the data I want to put in the excel sheet :
let datos = [
{
"Dato 1" : 1,
"Dato 2" : 2,
"Dato 3" : 3
},
{
"Dato 1" : 4,
"Dato 2" : 5,
"Dato 3" : 6
},
{
"Dato 1" : 7,
"Dato 2" : 8,
"Dato 3" : 9
}
]
When I only call the function to put data, this happens Works fine it pull all the data in the correct way:
function caller() {
// console.log('Deleting previous data...')
// deleteAllExcelRows(woorksheet)
// console.log('Data eliminated\n')
console.log("Put new data...\n");
for (let i = 0; i < datos.length; i++) {
putDataExcel(woorksheet,datos,i);
}
}
caller()
When I only call the function to delete the data also works fine,deletes all the data except the headers:
function caller() {
console.log('Deleting previous data...')
deleteAllExcelRows(woorksheet)
console.log('Data eliminated\n')
// console.log("Put new data...\n");
// for (let i = 0; i < datos.length; i++) {
// putDataExcel(woorksheet,datos,i);
// }
}
caller()
Now if I called both something very weird happens, the last elements of the data is repeated:
function caller() {
console.log('Deleting previous data...')
deleteAllExcelRows(woorksheet)
console.log('Data eliminated\n')
console.log("Put new data...\n");
for (let i = 0; i < datos.length; i++) {
putDataExcel(woorksheet,datos,i);
}
}
caller()
INCORRECT RESULT :
Desire result :
Complete code :
const xlsx = require("xlsx");
const FILENAME = "C:\\Users\\harol\\Documents\\prueba-excel.xlsx"
let wb = xlsx.readFile(FILENAME);
let woorksheet = wb.Sheets[wb.SheetNames[0]];
let datos = [
{
"Dato 1" : 1,
"Dato 2" : 2,
"Dato 3" : 3
},
{
"Dato 1" : 4,
"Dato 2" : 5,
"Dato 3" : 6
},
{
"Dato 1" : 7,
"Dato 2" : 8,
"Dato 3" : 9
}
]
function putDataExcel(ws,data,i) {
let hoja = xlsx.utils.sheet_to_json(ws);
console.log(xlsx.utils.decode_range(ws["!ref"]))
hoja.push(data[i]);
xlsx.utils.sheet_add_json(ws, hoja);
xlsx.writeFile(wb, FILENAME);
}
function ec(row, column) {
return xlsx.utils.encode_cell({ r: row, c: column });
}
function deleteExcelRow(ws, row_index) {
let hoja = xlsx.utils.sheet_to_json(ws);
console.log(xlsx.utils.decode_range(ws["!ref"]))
let range = xlsx.utils.decode_range(ws["!ref"]);
for (var R = row_index; R < range.e.r; ++R) {
for (var C = range.s.c; C <= range.e.c; ++C) {
ws[ec(R, C)] = ws[ec(R + 1, C)];
}
}
range.e.r--;
ws["!ref"] = xlsx.utils.encode_range(range.s, range.e);
xlsx.writeFile(wb, FILENAME);
console.log(xlsx.utils.decode_range(ws["!ref"]))
console.log("\n")
}
function deleteAllExcelRows(ws)
{
let numeroFilas = parseInt(xlsx.utils.decode_range(ws['!ref']).e.r)
for(let i = 1;i<=numeroFilas;i++)
{
deleteExcelRow(ws,i);
console.log("Dato " + i + "Eliminado ")
}
}
function caller() {
console.log('Deleting previous data...')
deleteAllExcelRows(woorksheet)
console.log('Data eliminated\n')
console.log("Put new data...\n");
for (let i = 0; i < datos.length; i++) {
putDataExcel(woorksheet,datos,i);
}
}
caller()
Why this happens and how I can solve it ?

Related

reducing an array of nested objects in javascript

so i have this array and i want to return the sum of lci and the sum of mci with a reduce function
const data = [{ option:{ lci: 1, mci: 2 } }, { option:{ lci: 3, mci: 4 } }, { option:{ lci: 5, mci: 6 } }];
i have tried this but it's not working:
data.reduce( (previousValue, currentValue) => {
return {
totalLCI: previousValue.option.lci + currentValue.option.lci,
totalMCI: previousValue.option.lci + currentValue.option.lci,
};
})
reduce method takes 2 important args: your reducing function and the default value at step 0 of the iteration
Here the reducer has 2 args:
the so-called previousValue: here called reducerTarget as it receives what is returned in the body of the reducer
the currentValue where the reducer is: here called currentArrayItem
Here's what you might want
const {totalLCI, totalMCI} = data.reduce((reducerTarget, currentArrayItem) => {
return {
totalLCI: reducerTarget.totalLCI + currentArrayItem.option.lci,
totalMCI: reducerTarget.totalMCI + currentArrayItem.option.mci
}
}, {totalLCI: 0, totalMCI: 0})
From here, starting with the default value, what it does on the first iteration is
/* 1st step:
index = 0
targetReducer = defaultValue = {totalMCI: 0, totalLCI: 0}
currentArrayItem = {option: {lci: 1, mci: 2}}
*/
return {
totalLCI: 0 + 1,
totalMCI: 0 + 2
}
/* 2nd step:
index = 1
targetReducer = previousValue = {totalMCI: 1, totalLCI: 2}
currentArrayItem = {option: {lci: 3, mci: 4}}
*/
return {
totalLCI: 1 + 3,
totalMCI: 2 + 4
}
First you need know if you have stored value in the fields totalLCI and totalMCI, if they aren't set, add the previous value and the current value, after add, return the values, in the next iteration, you will check again if the data is stored in totalLCI and totalMCI, after that, you will get data stored in that field and sum it all the time till finish the iteration, here an example:
var data2 = [{ option:{ lci: 1, mci: 2 } }, { option:{ lci: 3, mci: 4 } }, { option:{ lci: 5, mci: 6 } }];
let test = data2.reduce( (previousValue, currentValue) => {
if(!previousValue.totalLCI && !previousValue.totalMCI){
return {
totalLCI: previousValue.option.lci + currentValue.option.lci,
totalMCI: previousValue.option.mci + currentValue.option.mci
};
}else{
return{
totalLCI: previousValue.totalLCI + currentValue.option.lci,
totalMCI: previousValue.totalMCI + currentValue.option.mci
}
}
});
console.log(test.totalLCI);
console.log(test.totalMCI);

how to Check like status from an array of userIds mongoDb node Js in a single db hit?

I have an feed collection like this.
{
"_id" : ObjectId("5989986f93d2f911f44d58f0"),
"createdAt" : ISODate("2017-08-08T10:54:39.984Z"),
"updatedAt" : ISODate("2017-08-16T10:36:01.254Z"),
"subCategory" : "35",
"category" : "49",
"title" : "Toilet Ek Prem Katha Official Trailer | Akshay Kumar | Bhumi Pednekar | 11 Aug 2017",
"feedType" : "USER_VIDEO_OWN",
"userId" : "5989954993d2f911f44d58ef",
"rating" : [],
"share" : [],
"likes" : [
"597835b7efb7eb000436f5a1",
"5989951d6b97e904a0331091",
"5989954993d2f911f44d58ef",
"598994f26b97e904a0331090"
],
"isDeleated" : 0,
"isActive" : 1,
"lastComment" : null,
"rateCount" : 0,
"recommended" : 0,
"playCount" : 0,
"commentCount" : 11,
"likeCount" : 4,
"url" : "",
"text" : "Movie !!!!!!!!!!!!!!!",
"video" : "https://www.youtube.com/watch?v=ym4EJQ7XORk",
"image" : "",
"__v" : 0}
Their is an like array which contain those user's userIds who like this feed.
I want to get an like flag at the time of get feed if my userId exist in this array the flag true or 1 else flag is false or 0.
Currently i am using an extra for loop to achieve this but i think its not an good way.
for (var i = 0; i < data.length; i++) {
data[i].isLiked = 0;
for (var j = 0; j < data[i].likes.length; j++) {
var likedUserId = data[i].likes[j];
if (likedUserId == b.userId) {
data[i].isLiked = 1;
data[i].followStatus = 1;
data[i].likes = '';
}
}
}
You have to do 2 steps of Logic
1.Fetch the data from DB using Query
2.Check for whether the user liked that feed.
Overview of code:
var _ = require('underscore');
Db.find({}, function(err,res){
for (var i = 0; i < res.length; i++) {
if(_.conatins(data[i].likes), b.userId) {
res[i].isLiked = 1;
} else {
res[i].isLiked = 0;
}
}
})
Try this code
var data = require('./models/feed.js');//This is the schema I assumed it as data
app.get('/likes/:userId',function(req,res){
data.find({'likes':req.params.userId},function(err,result){
if(result == true){
res.json(result);
}
else if(result == false){
res.json("id does not exists");
}
else(err) res.json('false');
});
});
Here in my code if you pass a userId through parameters you will get the response you want.Hope this helps for you.

values get undefined after then of promise nodejs

I'm facing a problem with my code... I make a query to my DB to check if a mac address of a array of macs is on the DB. If I have any result I return the count of macs in my DB and if is > 0 then I don't add nothing cause the mac already is listed, but if my result.count = 0 then I will add a new record.
My new record just have the mac address. For this I'm trying:
var countRepetidos = 0
var countPromises = []
if (obj.data.list != {} && obj.data.list.length > 0) {
var aux = obj.data["list"]
countRepetidos = 0
for (var i = 0; i < aux.length; i++) {
countPromises.push(Database.Probing.getMacAdress(aux[i]).then(function(data) {
console.log("probing countPromises aux[i] ", aux[i])
if (data.count > 0) {
countRepetidos += 1
} else {
Database.Probing.addMac(aux[i])
}
return Promise.resolve()
}))
}
Promise.all(countPromises).then(() => {
dataRepeated = [obj.data.stats.since, countRepetidos]
listaRepeated.push(dataRepeated)
console.log("probing listaRepeated --> ", listaRepeated)
if (listaRepeated != [] && (listaRepeated[0][0] != undefined && listaRepeated[0][1] != undefined)) {
Database.Probing.getLastTimestamp("probing_repeated", device.id).then(function(data) {
var lastTimestamp = data.date_part
console.log('probing lastTimestamp ', lastTimestamp * 1000)
if (lastTimestamp != listaRepeated[0][0] / 1000) {
Controllers.Agregate.agregateData("probing_repeated", 5 * 60, listaRepeated, dbHistConnectionString, device.id, device.network_id, device.organization_id, ["time", "clients"])
}
})
}
})
}
The problem is after the then of Database.Probing.getMacAddress my aux[i] gets undefined and I need this value to insert into my DB.
Anyone can help?
You need to preserve the value of i. You can do this way:
for (var i = 0; i < aux.length; i++) {
(function(i) {
countPromises.push(
Database.Probing.getMacAdress(aux[i]).then(function(data) {
console.log("probing countPromises aux[i] ", aux[i])
if (data.count > 0) {
countRepetidos += 1
} else {
Database.Probing.addMac(aux[i])
}
return Promise.resolve()
}))
})(i)
}
Edit 1: As suggested by #lain, use let over var
for (let i = 0; i < aux.length; i++) {}

How to change a color of one particular bar using jqplot and stacked bar chart

I got one straight forward question. Is it possible to change the color of one bar in stacked bar chart in any way (using jqplot options or relying on a hack)?
I have this:
I want this:
So as you can already assume I am using 3 different colors for the stacked bar chart:
seriesColors: ['#afafaf', '#c4c6c4', '#dbdcdd']
Problem is that I want to add one specific color for 1 particular bar.
Here is the JS code:
$(document).ready(
function() {
var el = [ 3, 6, 0, 10, 12 ];
var ael = [ 14, 5, 0, 4, 2 ];
var ipv = [ 4, 9, 0, 8, 4 ];
var months = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May' ];
var colors = ['blue', 'red', 'white'];
plot3 = $.jqplot('elDiagram', [ el, ael, ipv ], {
stackSeries : true,
seriesColors: colors,
captureRightClick : true,
seriesDefaults : {
renderer : $.jqplot.BarRenderer,
rendererOptions : {
barMargin : 30,
varyBarColor : true,
highlightMouseDown : true,
barWidth: 60
},
pointLabels : {
show : true
}
},
axes : {
xaxis : {
renderer : $.jqplot.CategoryAxisRenderer,
ticks : months,
tickOptions : {
mark : 'outside'
}
},
yaxis : {
tickOptions : {
show : false
},
padMin : 0
}
},
series : [ {
label : 'bla1'
}, {
label : 'bla2'
}, {
label : 'bla3'
} ],
legend : {
show : true,
location : 'ne',
placement : 'inside'
}
});
});
Thanks!
OK, the solution was a hack which I will show and describe here:
You need to overwrite the function called $.jqplot.BarRenderer.prototype.draw and change some of the lines
You need to overwrite the function called getStart(sidx, didx, comp, plot, axis)
You need to overwrite the function called $.jqplot.ShapeRenderer.prototype.draw and change some of the lines
1.:
$.jqplot.BarRenderer.prototype.draw = function(ctx, gridData, options, plot) {
var i;
// Ughhh, have to make a copy of options b/c it may be
// modified later.
var opts = $.extend({}, options);
.................................
<other code>
.................................
var clr = opts.fillStyle || this.color;
this._dataColors.push(clr);
this.renderer.shapeRenderer.draw(ctx, points, opts, i, pos); // changed line
I changed the line in that way that I added i and pos parameters into the function. The reason was to indicate the current bar and position in the bar.
2.:
function getStart(sidx, didx, comp, plot, axis) {
// check if sign change
var seriesIndex = sidx, prevSeriesIndex = sidx - 1, start, prevVal, aidx = (axis === 'x') ? 0 : 1;
// is this not the first series?
if (seriesIndex > 0) {
prevVal = plot.series[prevSeriesIndex]._plotData[didx][aidx];
// is there a sign change
if ((comp * prevVal) < 0) {
start = getStart(prevSeriesIndex, didx, comp, plot, axis);
}
// no sign change.
else {
start = plot.series[prevSeriesIndex].gridData[didx][aidx];
}
}
// if first series, return value at 0
else {
start = (aidx === 0) ? plot.series[seriesIndex]._xaxis.series_u2p(0) : plot.series[seriesIndex]._yaxis.series_u2p(0);
}
return start;
}
Nothing is changed here. You just need to copy the function because your new overwritten function cannot use it from jQPlot library.
3.:
$.jqplot.ShapeRenderer.prototype.draw = function(ctx, points, options, currentBar, position) {
ctx.save();
var opts = (options != null) ? options : {};
var fill = (opts.fill != null) ? opts.fill : this.fill;
var closePath = (opts.closePath != null) ? opts.closePath : this.closePath;
var fillRect = (opts.fillRect != null) ? opts.fillRect : this.fillRect;
var strokeRect = (opts.strokeRect != null) ? opts.strokeRect
: this.strokeRect;
var clearRect = (opts.clearRect != null) ? opts.clearRect : this.clearRect;
var isarc = (opts.isarc != null) ? opts.isarc : this.isarc;
var linePattern = (opts.linePattern != null) ? opts.linePattern
: this.linePattern;
var ctxPattern = $.jqplot.LinePattern(ctx, linePattern);
ctx.lineWidth = opts.lineWidth || this.lineWidth;
ctx.lineJoin = opts.lineJoin || this.lineJoin;
ctx.lineCap = opts.lineCap || this.lineCap;
ctx.strokeStyle = (opts.strokeStyle || opts.color) || this.strokeStyle;
ctx.fillStyle = opts.fillStyle || this.fillStyle;
if (currentBar == activeColumn && position == 0) { // adding different color for the specific bar
ctx.fillStyle = defaultColors[0];
} else if (currentBar == activeColumn && position == 1) {
ctx.fillStyle = defaultColors[1];
} else if (currentBar == activeColumn && position == 2) {
ctx.fillStyle = defaultColors[2];
}
ctx.beginPath();
if (isarc) {
ctx.arc(points[0], points[1], points[2], points[3], points[4], true);
if (closePath) {
ctx.closePath();
}
if (fill) {
ctx.fill();
} else {
ctx.stroke();
}
ctx.restore();
return;
} else if (clearRect) {
ctx.clearRect(points[0], points[1], points[2], points[3]);
ctx.restore();
return;
} else if (fillRect || strokeRect) {
if (fillRect) {
ctx.fillRect(points[0], points[1], points[2], points[3]);
}
if (strokeRect) {
ctx.strokeRect(points[0], points[1], points[2], points[3]);
ctx.restore();
return;
}
} else if (points && points.length) {
var move = true;
for ( var i = 0; i < points.length; i++) {
// skip to the first non-null point and move to it.
if (points[i][0] != null && points[i][1] != null) {
if (move) {
ctxPattern.moveTo(points[i][0], points[i][1]);
move = false;
} else {
ctxPattern.lineTo(points[i][0], points[i][1]);
}
} else {
move = true;
}
}
if (closePath) {
ctxPattern.closePath();
}
if (fill) {
ctx.fill();
} else {
ctx.stroke();
}
}
ctx.restore();
};
Here you need to check whether the bar your currently at, is the default one. The important part of the code is:
if (currentBar == activeColumn && position == 0) { // adding different color for the specific bar
ctx.fillStyle = defaultColors[0];
} else if (currentBar == activeColumn && position == 1) {
ctx.fillStyle = defaultColors[1];
} else if (currentBar == activeColumn && position == 2) {
ctx.fillStyle = defaultColors[2];
}
I added 3 different colors for that bar just to have "more fancy" diagram :)

Couchbase/CouchDB grouping by part of key and ordering by another part

I've got a database of messages between users. Document looks like:
"_id": "msg_0bec56c1-cbfb-47a5-8882-4a61fec332cd",
"_rev": "1-00000eda4d07c93d0000009100000112",
"$flags": 0,
"$expiration": 0,
"Date": 1340280439303,
"OwnerId": 35,
"RcptId": 37,
"SndrId": 35,
"Text": "msg5",
"Unread": false,
"id": "0bec56c1-cbfb-47a5-8882-4a61fec332cd",
"type": "msg"
For each message it stores 2 documents with different OwnerId. I need to get the lastest message between one specified person and 10 uniqe "pen friends" ordered by last message date.
My query params:
descending=true&endkey=[35,35]&startkey=[35,35,"{}"]&limit=10&skip=0
My map function:
function (doc) {
if (doc.type == "msg"){
emit([doc.OwnerId, doc.SndrId, doc.Date, doc.RcptId], doc);
emit([doc.OwnerId, doc.RcptId, doc.Date, doc.SndrId], doc);
}
}
As a result I get list of messages for desired account. Last value (4th) in key is that value on which we should group values.
Groupping with group level 4 not working because dates are different.
Here is my new map function that does exactly what i've wanted BUT only if I have one server.
var uniqPairs = [];
function(doc){
if (doc.type == "msg"){
if (doc.OwnerId == doc.SndrId){
if (uniqPairs.indexOf(doc.OwnerId + "_" + doc.RcptId) == -1){
uniqPairs.push(doc.SndrId + "_" + doc.RcptId);
uniqPairs.push(doc.RcptId + "_" + doc.SndrId);
emit([doc.OwnerId, doc.Date], {"owner": doc.OwnerId, "from":doc.SndrId, "to":doc.RcptId});
}
}
if (doc.OwnerId == doc.RcptId){
if (uniqPairs.indexOf(doc.OwnerId + "_" + doc.SndrId) == -1){
//uniqPairs.push(doc.SndrId + "_" + doc.RcptId);
uniqPairs.push(doc.RcptId + "_" + doc.SndrId);
emit([doc.OwnerId, doc.Date], {"owner": doc.OwnerId, "from":doc.SndrId, "to":doc.RcptId});
}
}
}
}
So for cluster I sacrificed "ordering by date" and got such functions for map/reduce:
Map:
function (doc) {
if (doc.type == "msg"){
if (doc.OwnerId == doc.SndrId){
emit([doc.OwnerId, doc.RcptId, doc.Date], {"Date":doc.Date, "OwnerId":doc.OwnerId, "RcptId":doc.RcptId, "SndrId":doc.SndrId, "Text":doc.Text, "Unread":doc.Unread, "id": doc.id, "type":doc.type});
} else {
emit([doc.OwnerId, doc.SndrId, doc.Date], {"Date":doc.Date, "OwnerId":doc.OwnerId, "RcptId":doc.RcptId, "SndrId":doc.SndrId, "Text":doc.Text, "Unread":doc.Unread, "id": doc.id, "type":doc.type});
}
}
}
Reduce:
var tmp = [];
var t = [];
function findRecent(arr){
var max = 0;
var maxId = 0;
for (var i in arr){
if (arr[i].Date > max){
max = arr[i].Date;
maxId = i;
}
}
return arr[maxId];
}
function(k,v,r){
if (!r){
tmp.push(v);
}
else{
tmp.push(v);
}
if (r){
for (var i1 in tmp[0])
{
t.push(tmp[0][i1]);
}
} else {
return findRecent(v);
}
return findRecent(t);
}
If someone knows better solution (i.e. how to oreder results by date) - you're welcome to answer.

Resources