AutoFilter and Sorting — Conditional Filters, Sort, and Reading Conditions Back

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

What you want to do

Set an AutoFilter on a data table so that only rows matching a condition are shown, and sort (ascending / descending) with Sort. A filter works by hiding the rows that do not match the condition; whether a row is hidden can be read with Row.getHidden().

ApproachWhat to use
Set filter / conditionsws.getAutoFilter(range, firstRowAsHeader) → the set*Filter methods on AutoFilter
Clear conditionsaf.resetAllFilter() (conditions only) / af.removeFilter() (removes the filter itself)
Sortws.getSort(range) / af.getSort() → executeSortAscending / executeSortDescending
Check hidden rowsws.getRow(r).getHidden()

Classes covered

nodeosbxl.AutoFilter — obtained via ws.getAutoFilter(A1C1, firstRowAsHeader?)

MethodDescription
getAddress()Returns the target cell range.
setCustomFilter(op, criteria, colId?)Filter with an operator + criteria. criteria supports the * and ? wildcards.
setAndCustomFilter(op1, c1, op2, c2, colId?) / setOrCustomFilter(...)AND / OR combination of two conditions.
setTop10ValueFilter(n, colId?) / setBottom10ValueFilter(n, colId?)Top / bottom n rows by value.
setTop10PercentFilter(p, colId?) / setBottom10PercentFilter(p, colId?)Top / bottom p percent by value.
setAverageFilter(aboveAverage, colId?)Above average (true) / below average (false).
setUniqueValuesNumberFilter(vals, colId?)Show only rows matching one of the numbers in the list.
setUniqueValuesStringFilter / setUniqueValuesDateTimeFilterString / date-time versions (see Caveats).
setDateTimeFilter / setDateTimeGroupingFilterDate period / grouping conditions.
setFontColorFilter / setCellColorFilter / setIconFilterConditions based on color / icon.
getSort()Returns a Sort that protects the header row.
resetFilter(colId) / resetAllFilter()Clear conditions (the filter itself remains).
removeFilter()Removes the AutoFilter itself and restores hidden rows.

op is enums.XlAutoFilterOperator:

ValueNumberMeaning
Equal1equal to
LessThan2less than
LessThanOrEqual3less than or equal to
NotEqual4not equal to
GreaterThanOrEqual5greater than or equal to
GreaterThan6greater than

nodeosbxl.Sort — obtained via ws.getSort(A1C1, firstRowAsHeader?) or af.getSort()

MethodDescription
executeSortAscending(target, direction?, matchCase?)Sorts ascending. target is the column number within the range (first column = 1).
executeSortDescending(target, direction?, matchCase?)Sorts descending.
execute(sortFieldObject)Sorts by a single dto.SortFieldObject (configure it with setSortOnValues(target, ascending)).
executeMultiple([...])Multi-key sort (works correctly since the 2026-10-01 fix. See Caveats).
getSortConditions()Reads back the configured conditions as an array of dto.SortFieldObject.
resetSort(target) / resetAllSort()Clear conditions. Only effective on a Sort obtained via AutoFilter / Table.

direction is enums.XlRowCol (Rows = 1 / Columns = 2). The default is Rows (sort rows).

Code

Output:

// af-sort.js — AutoFilter and sorting
const { nodeosbxl, enums } = require("nodeosbxl");

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

// ---------- 1. prepare data (header + 10 rows) ----------
const DATA = [
    ["Apple", "Tokyo", 120, 100],
    ["Orange", "Osaka", 40, 80],
    ["Banana", "Tokyo", 200, 150],
    ["Grape", "Fukuoka", 60, 300],
    ["Pear", "Osaka", 90, 120],
    ["Peach", "Fukuoka", 150, 400],
    ["Kiwi", "Tokyo", 30, 90],
    ["Mango", "Osaka", 70, 500],
    ["Strawberry", "Fukuoka", 110, 350],
    ["Melon", "Tokyo", 25, 800],
];
["Product", "Region", "Qty", "Unit Price"].forEach((h, i) =>
    ws.getRange(`${"ABCD"[i]}1:${"ABCD"[i]}1`).setValue(h));
DATA.forEach((row, i) => {
    const r = i + 2;
    ws.getRange(`A${r}:A${r}`).setValue(row[0]);
    ws.getRange(`B${r}:B${r}`).setValue(row[1]);
    ws.getRange(`C${r}:C${r}`).setNumberValue(row[2]);
    ws.getRange(`D${r}:D${r}`).setNumberValue(row[3]);
});
console.log("[1] data ready: A1:D11 (header + 10 rows)");

// display helpers: row number → "Product(value)" / list of rows that are not hidden
const text = (r, col) => ws.getRange(`${col}${r}:${col}${r}`).getValue()[`${col}${r}`];
const label = (r, col) => `${text(r, "A")}(${text(r, col)})`;
const visible = (col) => {
    const out = [];
    for (let r = 2; r <= 11; r++) if (!ws.getRow(r).getHidden()) out.push(label(r, col));
    return out.join(" ");
};
const hiddenList = () => {
    const out = [];
    for (let r = 2; r <= 11; r++) if (ws.getRow(r).getHidden()) out.push(r);
    return out.length ? out.join(",") : "none";
};

// ---------- 2. set up the AutoFilter ----------
const af = ws.getAutoFilter("A1:D11", true);   // first row is the header
console.log(`[2] getAutoFilter → range = ${af.getAddress()} / hidden rows = ${hiddenList()}`);

// ---------- 3. custom filter: Qty > 100 ----------
// colId is the column number within the range (A=1 … D=4). Do not put operator symbols in criteria
af.setCustomFilter(enums.XlAutoFilterOperator.GreaterThan, "100", 3);
console.log(`[3] visible rows with Qty>100: ${visible("C")}`);
console.log(`    hidden rows = ${hiddenList()} / getValue("A2:A11") count = ${Object.keys(ws.getRange("A2:A11").getValue()).length}`);
af.resetAllFilter();                            // clear conditions only (the filter itself remains)

// ---------- 4. Top-N / value-list filters ----------
af.setTop10ValueFilter(3, 3);                   // top 3 by Qty
console.log(`[4] visible rows in top 3 by Qty: ${visible("C")}`);
af.resetAllFilter();
af.setUniqueValuesNumberFilter([120, 40], 3);   // Qty is 120 or 40
console.log(`[5] visible rows with Qty in {120,40}: ${visible("C")}`);
af.resetAllFilter();
af.setUniqueValuesStringFilter(["Tokyo", "Fukuoka"], 2);   // Region is Tokyo or Fukuoka (string list)
console.log(`[6] visible rows with Region in {Tokyo,Fukuoka}: ${visible("B")}`);
af.resetAllFilter();
af.setCustomFilter(enums.XlAutoFilterOperator.Equal, "Osaka", 2);   // Region = Osaka (string match)
console.log(`[7] visible rows with Region="Osaka": ${visible("B")}`);
af.resetAllFilter();

// ---------- 5. sorting (single key) ----------
// target only the data rows without the header (firstRowAsHeader omitted = false)
ws.getSort("A2:D11").executeSortAscending(3);   // ascending by Qty (3rd column within the range)
console.log(`[8] ascending by Qty: ${visible("C")}`);

// a Sort obtained via the AutoFilter protects the header row automatically
const sort = af.getSort();
sort.executeSortDescending(4);                  // descending by Unit Price (4th column)
console.log(`[9] descending by Unit Price: ${visible("D")}`);

// ---------- 6. read the sort conditions back ----------
const cond = sort.getSortConditions()[0];
console.log(`[10] condition read back: target column = ${cond.getTarget()} / ascending = ${cond.getSortAscending()}`);

// ---------- 7. remove the AutoFilter itself ----------
af.removeFilter();
console.log(`[11] after removeFilter: hidden rows = ${hiddenList()}`);

wb.save();
wb.close();
[1] data ready: A1:D11 (header + 10 rows)
[2] getAutoFilter → range = A1:D11 / hidden rows = none
[3] visible rows with Qty>100: Apple(120) Banana(200) Peach(150) Strawberry(110)
    hidden rows = 3,5,6,8,9,11 / getValue("A2:A11") count = 10
[4] visible rows in top 3 by Qty: Apple(120) Banana(200) Peach(150)
[5] visible rows with Qty in {120,40}: Apple(120) Orange(40)
[6] visible rows with Region in {Tokyo,Fukuoka}: Apple(Tokyo) Banana(Tokyo) Grape(Fukuoka) Peach(Fukuoka) Kiwi(Tokyo) Strawberry(Fukuoka) Melon(Tokyo)
[7] visible rows with Region="Osaka": Orange(Osaka) Pear(Osaka) Mango(Osaka)
[8] ascending by Qty: Melon(25) Kiwi(30) Orange(40) Grape(60) Mango(70) Pear(90) Strawberry(110) Apple(120) Peach(150) Banana(200)
[9] descending by Unit Price: Melon(800) Mango(500) Peach(400) Strawberry(350) Grape(300) Banana(150) Pear(120) Apple(100) Kiwi(90) Orange(80)
[10] condition read back: target column = 4 / ascending = false
[11] after removeFilter: hidden rows = none

Notes

Filters = hiding rows

An AutoFilter only hides the rows that do not match the condition; no data is deleted.

Writing filter conditions

Sorting

Caveats

See also