5

I have a spreadsheet with two sheets. Sheet 1 contains 3 columns with 100s of rows of data (strings). Sheet 2 is to be used as a mastersheet of correct combinations for Sheet 1 to be checked against to make sure the values in in cell are correct. Sheet 2 has 3 columns also.

What I would like to do is loop through Sheet 1 row by row, and check each cell's value in the row matches anywhere what is in Sheet 2, row by row.

If a check fails, then further checks on that row should cease and the next row to be checked commences. Cells in Sheet 1 that couldn't be matched should be marked red.

My code below is close to what I need, but is marking more cells incorrect than what is required.

// Import the library
var Excel = require('exceljs');
var moment = require('moment');
// Define Excel filename
var ExcelFile = 'so.xlsx';

// Read from the file
var workbook = new Excel.Workbook();
workbook.xlsx.readFile(ExcelFile)
    .then(function() {
        // Use workbook
        var dataSheet = workbook.getWorksheet('Sheet 1');
        var masterSheet = workbook.getWorksheet('Sheet 2');

        dataSheet.eachRow({ includeEmpty: false }, function(row, rowNumber) {

            var dataSheetCell1 = row.getCell('A').value;
            var dataSheetCell2 = row.getCell('B').value;
            var dataSheetCell3 = row.getCell('C').value;

            masterSheet.eachRow({ includeEmpty: false }, function(row, rowNumber) {

                var masterSheetCell1 = row.getCell('A').value;
                var masterSheetCell2 = row.getCell('B').value;
                var masterSheetCell3 = row.getCell('C').value;

                // Iterate over all cells in a row (including empty cells)
                row.eachCell({ includeEmpty: false }, function(cell, colNumber) {
                    if(dataSheetCell1 == masterSheetCell1) {
                        console.log(true)
                    } else {
                        // Stop all further checks for this sheet(n) row and move onto next row
                        // Mark this failed cell as color red
                    }
                });
            });
        });

        return workbook.xlsx.writeFile('new.xlsx');
    });

Example data would look like this:

Sheet 1:

| COL A | COL B  | COL C  |
|-------|--------|--------|
| bob   | eleven | blue   |
| bob   | eleven | blue   |
| bob   | eleven | red    |
| bob   | eleven | red    |
| bob   | one    | red    |
| bob   | eight  | red    |
| bob   | eight  | red    |
| bob   | eight  | red    |
| terry | seven  | yellow |
| terry | seven  | yellow |
| terry | seven  | gold   |

Sheet 2:

| COL A | COL B  | COL C  |
|-------|--------|--------|
| bob   | eleven | blue   |
| bob   | eleven | red    |
| bob   | eight  | red    |
| terry | seven  | yellow |
| terry | seven  | orange |

According to the sample data, there should be two errors (B5 and C11) that are marked red in Sheet 1 of new.xlsx. E.g.

enter image description here

This is an example PDF of how the checking should take place:

enter image description here

dom_ahdigital
  • 1,651
  • 18
  • 37

1 Answers1

4

You can mark each failed cell as color red like follows:

// Import the library
var Excel = require('exceljs'),
    moment = require('moment'),
    // Define Excel filename
    ExcelFile = 'so.xlsx',
    // Read from the file
    workbook = new Excel.Workbook();

workbook.xlsx.readFile(ExcelFile)
    .then(function()
    {
        // Use workbook
        var dataSheet = workbook.getWorksheet('Sheet 1'),
            masterSheet = workbook.getWorksheet('Sheet 2');

        dataSheet.eachRow({ includeEmpty: false }, function(dataRow, dataRowNumber)
        {
            var dataRowCells =
                {
                    dataCell1: dataRow.getCell('A'),
                    dataCell2: dataRow.getCell('B'),
                    dataCell3: dataRow.getCell('C')
                },
                isdataRowOK = false,
                oneOfBestMasterRowNumber,
                cellNames = ['A','B','C'];

            masterSheet.eachRow({ includeEmpty: false }, function(masterRow, masterRowNumber)
            {
                if(!isdataRowOK)
                {
                    var numberOfGoodCellsInRow = 0;

                    for(var i = 1; i < 4; i++)
                        if(dataRowCells['dataCell' + i].value === masterRow.getCell(cellNames[i-1]).value)
                            numberOfGoodCellsInRow++;

                    if(numberOfGoodCellsInRow == 2)
                        oneOfBestMasterRowNumber = masterRowNumber;

                    if(numberOfGoodCellsInRow == 3)
                        isdataRowOK = true
                }
            });


            if(!isdataRowOK)
            {
                var masterRowForCheck = masterSheet.getRow(oneOfBestMasterRowNumber);

                for(var i = 1; i < 4; i++)
                {
                    var dataCell = dataRowCells['dataCell' + i];
                    if(dataCell.value !== masterRowForCheck.getCell(cellNames[i-1]).value)
                    {
                        // Mark this failed cell as color red
                        dataCell.style = Object.create(dataCell.style); // Shallow-clone the style, break references
                        dataCell.fill = {type: 'pattern', pattern:'solid', fgColor:{argb:'FA8072'}}; // Set background
                    }
                }

            }
        });

        return workbook.xlsx.writeFile('new.xlsx');
    });
Bharata
  • 13,509
  • 6
  • 36
  • 50
  • Getting error when I try out different test data: `UnhandledPromiseRejectionWarning: Error: Invalid Address: Aundefined` and I think it gets thrown when there is more than 1 error cell within a single row of `dataSheet`. E.g. you can only have one error per row. – dom_ahdigital Dec 10 '18 at 09:57
  • @dom_ahdigital, I answered you like in your task description: _If a check fails, then further checks on **that row** should cease and the next row to be checked commences._ And then in your code *// Stop all further checks for this sheet(n) row and move onto next row*. The second problem: in your data we do not have this situation. And If I do it now like you want now then my code will be wrong to your task. And in SO rules we have the rule that you can not change the task when somebody has already answered. – Bharata Dec 11 '18 at 22:29
  • @dom_ahdigital, I would like to recommend you to write a new question and I will try to write you the solution. And please think good before what you want to have. – Bharata Dec 11 '18 at 22:29
  • @dom_ahdigital, as a workaround you can write instead of line `if(!isdataRowOK)` the following line: `if(!isdataRowOK && oneOfBestMasterRowNumber != 'undefined')` This should catch this error and may be you do not need nothing more for your data? – Bharata Dec 11 '18 at 23:45