Bulk Input of Large Data — setValueArray / setFormulaArray

level: intermediate / verified: 2026-10-01 / tabs: Node.js・Python・Java・WebAssembly / 日本語

What you want to do

Write values and formulas into thousands or tens of thousands of cells in one shot as an array instead of calling getRange() per cell. Also, bulk-input formulas whose relative references shift row by row.

ApproachWhat to use
Per-cell inputws.getCells(r, c).setNumberValue(...)
Bulk value inputws.setValueArray(Array<dto.InputValueObject>)
Bulk formula inputws.setFormulaArray(Array<dto.InputFormulaObject>)

Classes covered

dto.InputValueObject

MethodDescription
setStringValue(A1C1, val, numberFormat?)Sets a string value.
setNumberValue(A1C1, val, forceString?, numberFormat?)Sets a number.
setBooleanValue(A1C1, val, forceString?, numberFormat?)Sets a boolean.
setDateTimeValue(A1C1, val, forceString?, numberFormat?)Sets a date/time value.
setEmptyVal(A1C1)Clears the cell range.
getA1C1() / getInputType() / getStringValue() / getNumberValue() / getBooleanValue() / getDateTimeValue() / getNumberFormat() / getForceString()Read back the configured content.

dto.InputFormulaObject

MethodDescription
setA1C1(A1C1)Sets the target cell.
setFormula(formula)Sets the formula (no leading =).
getA1C1() / getFormula()Read back the configured content.

Code

Output:

// bulk-input.js — bulk input of values and formulas, speed comparison against per-cell input
const { nodeosbxl, dto } = require("nodeosbxl");

const app = new nodeosbxl.App();
const wb = app.createWorkBook("bulk-input.xlsx");
const ws = wb.openWorkSheet("Sheet1");

// ---------- 1. write mixed types in one shot ----------
const date = new dto.DateTimeObject();
date.setYMD(2024, 3, 20);

const values = [];
const addString = (a1, val) => {
    const o = new dto.InputValueObject();
    o.setStringValue(a1, val);
    values.push(o);
};
// Trailing optional arguments can be passed as undefined (treated as omitted)
const addNumber = (a1, val, fmt) => {
    const o = new dto.InputValueObject();
    o.setNumberValue(a1, val, false, fmt);
    values.push(o);
};

addString("A1", "Product");
addNumber("B1", 1234.5);
addNumber("C1", 0.25, "0.0%");
// Date: omitting the format auto-sets a default format (same as Range.setDateValue)
const dateVal = new dto.InputValueObject();
dateVal.setDateTimeValue("D1", date, false, "yyyy-mm-dd");   // explicit format
values.push(dateVal);
const dateVal2 = new dto.InputValueObject();
dateVal2.setDateTimeValue("D2", date);                       // omitted → auto
values.push(dateVal2);

ws.setValueArray(values);
console.log("[1] bulk input with mixed types");
for (const a1 of ["A1", "B1", "C1", "D1", "D2"]) {
    const r = ws.getRange(`${a1}:${a1}`);
    console.log(`    ${a1}: display=${JSON.stringify(r.getValue()[a1])} format=${JSON.stringify(r.getNumberFormat()[a1])}`);
}

// ---------- 2. clearing cells is bulk input too ----------
ws.getRange("A2:A2").setValue("temporary entry");
const empty = new dto.InputValueObject();
empty.setEmptyVal("A2");
ws.setValueArray([empty]);
console.log("[2] after setEmptyVal, A2 =", JSON.stringify(ws.getRange("A2:A2").getValue()["A2"]));

// ---------- 3. bulk-input formulas with relative references shifted per row ----------
// Range.setFormula() does not expand relative references, so use this instead
for (let r = 1; r <= 3; r++) ws.getRange(`F${r}:F${r}`).setNumberValue(r * 10);
const formulas = [];
for (let r = 1; r <= 3; r++) {
    const f = new dto.InputFormulaObject();
    f.setA1C1(app.convertFromRowColNumber(r, 7));   // G1, G2, G3
    f.setFormula(`F${r}*2`);                        // different relative reference per row
    formulas.push(f);
}
ws.setFormulaArray(formulas);
console.log("[3] after setFormulaArray");
console.log("    formulas =", JSON.stringify(ws.getRange("G1:G3").getFormula()));
console.log("    values   =", JSON.stringify(ws.getRange("G1:G3").getValue(true)));

// ---------- 4. speed comparison (2,000 rows x 5 cols = 10,000 cells) ----------
const ROWS = 2000, COLS = 5;

const wsCell = wb.addWorkSheet("CellByCell");
let t = Date.now();
for (let r = 1; r <= ROWS; r++) {
    for (let c = 1; c <= COLS; c++) wsCell.getCells(r, c).setNumberValue(r * 100 + c);
}
const msCell = Date.now() - t;

const wsBulk = wb.addWorkSheet("Bulk");
const bulk = [];
t = Date.now();
for (let r = 1; r <= ROWS; r++) {
    for (let c = 1; c <= COLS; c++) {
        const o = new dto.InputValueObject();
        o.setNumberValue(app.convertFromRowColNumber(r, c), r * 100 + c);
        bulk.push(o);
    }
}
const msBuild = Date.now() - t;
t = Date.now();
wsBulk.setValueArray(bulk);
const msApply = Date.now() - t;

console.log(`[4] writing ${ROWS * COLS} cells`);
console.log(`    per-cell getCells().setNumberValue() : ${msCell} ms`);
console.log(`    setValueArray (build ${msBuild} + write ${msApply}) : ${msBuild + msApply} ms`);

const a = wsCell.getRange("E2000:E2000").getValue(true)["E2000"];
const b = wsBulk.getRange("E2000:E2000").getValue(true)["E2000"];
console.log(`[check] both methods agree: E2000 = ${a === b ? a : `mismatch ${a} / ${b}`}`);

wb.save();
wb.close();
[1] bulk input with mixed types
    A1: display="Product" format="General"
    B1: display="1234.5" format="General"
    C1: display="25.0%" format="0.0%"
    D1: display="2024-03-20" format="yyyy-mm-dd"
    D2: display="2024/3/20" format="yyyy/m/d;@"
[2] after setEmptyVal, A2 = ""
[3] after setFormulaArray
    formulas = {"G1":"F1*2","G2":"F2*2","G3":"F3*2"}
    values   = {"G1":"20","G2":"40","G3":"60"}
[4] writing 10000 cells
    per-cell getCells().setNumberValue() : 102 ms
    setValueArray (build 18 + write 58) : 76 ms
[check] both methods agree: E2000 = 200005

The ms values in [4] change with every run (the above is one example run).

Notes

Speed

CellsPer-cell getCells().setNumberValue()setValueArray()Difference
10,000 (2,000 rows x 5 cols)~110 ms76 ms (build 18 + write 58)~1.4x
100,000 (20,000 rows x 5 cols)1,390 ms770 ms (build 130 + write 640)~1.8x

Both rows are single measured runs on osbxl 1.5.0 / Node.js v21; results vary with the environment and between runs. As a trend, the gap widens as the cell count grows. **The time spent assembling InputValueObjects on the JavaScript side is not negligible either**, which is why the measurements above separate "build" from "write". If you need to write tens of thousands of cells or more, use setValueArray().

When to use which

Caveats

See also