Nodes/Nova Audio Player/Nova SQLite Data Table & Filter ๐Ÿ”Ž
ComfyUI Node

Nova SQLite Data Table & Filter ๐Ÿ”Ž

Nova SQLite Data Table & Filter ๐Ÿ”Ž

By NovaFemmeยทCreated 2 months agoยทUpdated 15 days agoยท 1
Nova SQLite Data Table & Filter ๐Ÿ”Ž
  • row_data_json
  • table
  • row_data_json
  • rows_json
  • matched_rows
  • total_rows
  • where_clause
  • table
  • selected_rows
โ—„where_json[]โ–บ
โ—„selected_rows[]โ–บ
โ—„output_rowsmatching rowsโ–บ
โ—„case_sensitivefalseโ–บ
โ—„max_display_rows200โ–บ

What it's for

Batch work ends up in a table eventually. You generate forty ACE-Step tracks, you want the twelve tagged blues with a bpm under 100, and the moment you hand-edit a list between runs, batch processing stops being worth it. This node decides which rows the rest of your workflow even sees:

Browser โ”€โ–บ Data Table & Filter โ”€โ–บ Row Iterator  (or Single Row Filter)

The Nova Dynamic SQLite Browser reads a database out of ComfyUI's input/ folder and outputs rows. The Row Iterator loops one row per run and emits each column as its own output, so artist and bpm become wires you can feed into a prompt. In between, this node shows the whole table as an interactive grid and narrows it with conditions you build from dropdowns. The author's framing is blunt and right: you never write SQL, and the word WHERE never appears.

How it works

Filtering happens in Python, over rows already in memory. Conditions are stored as structured JSON (where_json), never assembled into a statement, so a value like O'Brien, 50% off or the classic x'; DROP TABLE albums;-- is only ever compared as text - a better answer than "we sanitised it carefully."

The SQL still exists, separately, on where_clause, and it escapes properly: quotes doubled, column names quoted, % and _ escaped for LIKE with ESCAPE '\' so they match literally instead of acting as wildcards. Conditions combine left to right, so A AND B OR C reads as (A AND B) OR C, up to 16 of them, and the operators cover the arithmetic plus contains, does not contain, starts with, ends with, in list, not in list, is empty, is not empty. Numbers compare as numbers when both sides look numeric, as text otherwise.

In the grid you click to select, Ctrl/โŒ˜-click to add, Shift-click for a range, drag to sweep, with all / invert / none shortcuts. The # column is the index the downstream nodes use, and selections are remembered by position - so a highlight survives changing conditions, re-running, and reloading the workflow.

Inputs and outputs worth knowing

Two of the six inputs are hidden in the UI and driven by the node itself - where_json (the condition builder) and selected_rows (clicking rows). You don't type into either.

The one you'll set is output_rows: matching rows (the default) passes everything the conditions matched, selected rows passes only what you highlighted - a hand-picked subset of a filter result, no export step. case_sensitive is off by default, which is what you want for text. max_display_rows (200) limits only what the grid shows; every match still passes on, so it can't silently truncate a batch.

Optionally connect row_data_json from the Browser, or a table (NOVA_TABLE) from another pack node to filter its rows instead. With both connected, row_data_json supplies the rows and table carries the database and table names forward.

Of the seven outputs: row_data_json is the pink wire into the Iterator or Single Row Filter, rows_json the same rows as a plain string, matched_rows and total_rows counters you can log, where_clause the escaped SQL, table the standard payload you wire into Nova Tag Writer, and selected_rows the count of highlighted rows.

Installing it

Nothing extra for this node - it comes with the pack:

comfy node install comfyui-novaaudioplayer
# or
cd ComfyUI/custom_nodes
git clone https://github.com/NovaFemme/ComfyUI-NovaAudioPlayer.git

Restart ComfyUI and hard-refresh (Ctrl + F5): all four SQLite nodes are custom JavaScript. The pack's declared packages, mutagen and pymysql, belong to its tagging and MySQL nodes; this one needs neither.

Databases go in ComfyUI/input/, top level or in sub-folders - .db, .sqlite, .sqlite3, scanned six levels deep, hidden folders skipped. Sub-folder databases appear by relative path. After copying one in, hit โŸณ to rescan; no restart needed.

Where people get burned

Press โ–ถ Execute before you queue anything. It walks the chain from the Browser outward and fills every display with real data - no prompt submitted, no other node runs, and it calls the same Python a real execution does. Skipping it is how people queue a forty-track batch against a filter they never looked at.

The errors are literal and all fixable. Nothing connected means wire the Browser to row_data_json; 0 columns selected means you haven't clicked any column badges on the Browser; No rows usually means the upstream query failed, not that the table is empty. And output_rows set to selected rows with nothing highlighted passes nothing on, with a warning.

Changing table or database costs you wires. The downstream nodes grow one output per selected column, so switching tables rebuilds that selection and the wired outputs vanish. The Browser warns you on-node first.

A condition on a dropped column shows red, not a wrong answer. Deselect a column a condition refers to and it's outlined and warned about instead of quietly changing your result. Selected-but-filtered-out rows are never passed on either - conditions always apply first.

Should you use it

If your workflow already has a Browser and an Iterator, yes - it's what makes that chain usable, since you pick rows in a grid instead of writing SQL against a .db file you can't see. Treat it as a filter for a Nova row pipeline, not a general SQLite client. For "take twelve specific tracks out of this library and run them," it's the shortest path in the pack.

Categoryโ–ถ๏ธ Nova Audio/๐Ÿ“ฆ Delivery & Metadata

Inputs (7)

NameTypeDefaultDescription
where_jsonSTRING[]Set by the condition builder on the node: the conditions, as a JSON list.
selected_rowsSTRING[]Set by clicking rows in the grid: the highlighted rows, as a JSON list.
output_rowsCOMBOmatching rowsWhich rows leave this node: everything the conditions match, or only the rows highlighted in the grid.
case_sensitiveBOOLEANfalseOff: text is matched regardless of upper / lower case
max_display_rowsINT2001โ€“10000How many rows the table shows. All matching rows are still passed on.
row_data_jsonoptNOVA_SQLITE_ROWSRows from the Nova Dynamic SQLite Browser.
tableoptNOVA_TABLEA NOVA_TABLE from any pack node, so its rows can be filtered too.

Outputs (7)

NameTypeDescription
row_data_jsonNOVA_SQLITE_ROWSThe rows leaving this node, for the Row Iterator and Single Row nodes.
rows_jsonSTRINGThe same rows as plain text.
matched_rowsINTHow many rows the conditions matched.
total_rowsINTHow many rows came in.
where_clauseSTRINGThe same conditions as SQL, safely escaped.
tableNOVA_TABLEThe same rows as a NOVA_TABLE, for Nova Tag Writer and the other pack nodes.
selected_rowsINTHow many rows are highlighted in the grid.