Desk Clarity

A field guide to everyday digital problems.

Developer tools / Practical guide

jq Filter Returns Separate Objects: Keep an Array with map(select)

Choose the expected output container before filtering JSON values.

By ON Lab2 min readSources checked November 10, 2026 (KST)

.[] | select(...) emits matching values as a stream. If the consumer expects one JSON array, keep the container with map(select(...)) or collect the stream explicitly. Quoting and pretty printing do not change that shape.

Reproduce the boundary in a disposable fixture

Choose the expected output container before filtering JSON values.

Use a new empty temporary directory for this fixture. The example creates only local test data. Commands marked with example.invalid do not identify a real service.

printf '%s
' '[{"id":1,"active":true},{"id":2,"active":false},{"id":3,"active":true}]' > input.json
jq '.[] | select(.active == true)' input.json > stream.json
jq 'map(select(.active == true))' input.json > array.json
jq -s 'length == 2' stream.json
jq -e 'type == "array" and length == 2 and .[1].id == 3' array.json
printf '%s
' '[]' | jq -e 'map(select(.active == true)) == []' 

Observed result

true
true
true

What the result means

The first output has two top-level object values. The second has one array containing those objects. An empty input array becomes an empty result array, which can be important for API callers expecting a stable container type. These examples intentionally compare the active property to true; they do not treat every non-null value as a boolean match.

Choose the correction for your workflow

Write down the consumer schema first: a single array, JSON Lines, or an arbitrary JSON value stream. For one input array, map(select(...)) usually expresses filtering directly. If you start from a stream instead, collect it with brackets only when the output size is bounded. Inspect the type of intermediate values when an error says you cannot index a string or array with a particular key. Filtering a nested array requires selecting that array first or deliberately updating its parent field; do not assume every document root is an array.

Limits and the next check

jq can process multiple top-level inputs, so map creates one output array per input array; it does not merge all documents automatically. Use a separate framing decision for that case. Avoid truthiness assumptions when false, null, zero and empty strings have different business meanings. The fixture uses small, known arrays and does not establish performance for a very large slurped file.

Related: Compare the related workflow boundary.

This isolated example was executed on macOS on November 10, 2026 (KST). Available tools: node v26.5.0, git git version 2.39.3 (Apple Git-145), npm 11.17.0, jq jq-1.7.1-apple. Shell fixtures use Bash and repository-path identity uses Python 3. This checks the illustrated contract, not your project, host service or every tool version.

Sources & further reading