_.matcher
Build a predicate that says 'got these attributes?' — the filter's best friend.
- py_dict
- attrs
- *
_.matcher returns a predicate - a function that answers "does this object contain all of these key/value pairs?" Feed it {"model": "flux"} and you get back a function that returns true for any dict that has model set to flux. That predicate is exactly what you want to hand to a filter, or to any of the underscore nodes that take a predicate as their iteratee. It's the object-shorthand branch of _.iteratee made standalone.
What it is
Part of the ovum/underscore family in sfinktah/comfy-ovum, wrapping the matcher method of underscore3, a Python port of Underscore.js. The returned predicate checks every key in the attrs dict against the candidate object - via obj.get(key) for dicts, or attribute access for non-dicts - and only returns true when every pair matches.
Inputs and the quirk in them
The schema lists two inputs:
py_dict(type*) - the primary input.attrs(type*) - described as the key/value pairs to match against, with JSON allowed.
Here's the thing I want you to understand before you trust that attrs socket: in the current code it doesn't actually map to a parameter. The port's matcher() takes no arguments - it builds the predicate from the object you feed into the primary input. So the attrs socket is effectively decorative in this version. Feed your attribute dict into py_dict instead, and the node works. This is exactly the kind of half-finished wiring the README warns about, and it's worth knowing so you don't spend an hour guessing why attrs seems to do nothing.
Output is typed * (ANY) - at runtime it's a Python function. Chain mode works: feed a _.CHAIN and get a chain back, resolved with _.value.
Where you'd use it
Filtering structured data. Build the matcher from {"tag": "sunset"}, then combine it with a filter-style node (or the underscore family's _.filter, which shares the predicate machinery) to keep only the entries that match. It's also useful for feature-flag style logic - "does this config object have these settings?" - as a gate on a conditional branch.
The caveat
Functions don't survive a save/reload as JSON, so the matcher you build lives only for the current session - rebuild it after reloading the workflow. And remember a matcher is a predicate, not a transformer: use it where a yes/no answer is what you need, and reach for _.map/_.mapObject when you want values changed.
Installing comfy-ovum
ComfyUI Manager: search for comfy-ovum, install, restart. Or by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/sfinktah/comfy-ovum
pip install -r comfy-ovum/requirements.txt
Restart and you're done. No model downloads, no CUDA - pure-Python utilities with a few small dependencies. Useful node, once you know to feed the matcher through the primary input.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| py_dictopt | * | Primary input object (expected object). You can still pass any JSON-serializable value. Also accepts _.CHAIN to continue chaining. | |
| attrsopt | * | attrs: JSON allowed for arrays/objects where applicable. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| * | * | — |