# JSON Array Sorter

Sort a JSON array of objects by one or more fields, ascending or descending. Supports nested dot-paths, per-key direction, missing-value placement, and minify.

## Run it

- **CLI:** `gizza tool sort-json-array '[ { "name": "Ada", "age": 36 }, { "name": "Bo", "age": 24 } ]' 'keys=dept,-salary,name'`
- **Web:** https://gizza.ai/tools/sort-json-array/
- **Agents:** machine-readable descriptor (parameters JSON Schema) at https://gizza.ai/tools/sort-json-array/tool.json

## Inputs

- `json` — JSON array _(field)_
- `keys` — Sort keys (comma-separated; '-' = descending) _(field)_
- `order` — Default direction _(field)_
- `missing` — Missing / null values _(field)_
- `case_insensitive` — Case-insensitive strings _(field)_
- `indent` — Indent spaces (0 = minify) _(field)_

## Output

- Sorted JSON (text)

## Query parameters

Open the tool pre-filled and auto-run via URL:

- `json` — JSON array
- `keys` — Sort keys (comma-separated; '-' = descending)
- `order` — Default direction
- `missing` — Missing / null values
- `case_insensitive` — Case-insensitive strings
- `indent` — Indent spaces (0 = minify)

Example: `https://gizza.ai/tools/sort-json-array/?json=%5B%20%7B%20%22name%22%3A%20%22Ada%22%2C%20%22age%22%3A%2036%20%7D%2C%20%7B%20%22name%22%3A%20%22Bo%22%2C%20%22age%22%3A%2024%20%7D%20%5D&keys=dept%2C-salary%2Cname&order=asc&missing=last&case_insensitive=true&indent=2`

---

## What this tool does

**JSON Array Sorter** reorders the elements of a JSON array of objects by the value of one
or more fields — the classic *ORDER BY* operation, but for a raw JSON array you can paste
straight from an API response, a log export, or a database dump. Give it one field or a
whole list, and it returns the same objects in a new order, ready to copy back out.

Each sort key can dig into **nested paths** with dot-notation (`address.city`, or the array
index `tags.0`), carry its own **direction** with a `+`/`-` prefix, and fall back to a global
ascending/descending default. You control where rows with a **missing or null** field land,
whether strings compare **case-insensitively**, and how the result is **indented** — or
minified onto a single line. It sorts array *elements* by a field; it never touches the keys
*inside* each object, so the shape of every record is preserved exactly.

## Worked example

**Input**

```json
[
  { "dept": "Eng", "salary": 120 },
  { "dept": "Ops", "salary": 90 },
  { "dept": "Eng", "salary": 150 }
]
```

With **keys = `dept,-salary`** (department ascending, then salary descending within each
department) and **indent = 2**, the output is:

```json
[
  {
    "dept": "Eng",
    "salary": 150
  },
  {
    "dept": "Eng",
    "salary": 120
  },
  {
    "dept": "Ops",
    "salary": 90
  }
]
```

The two `Eng` rows group together and sort highest-paid first; `Ops` follows. Set **indent
to `0`** to get the same order minified onto one line:
`[{"dept":"Eng","salary":150},{"dept":"Eng","salary":120},{"dept":"Ops","salary":90}]`.

## How to use it

1. Paste a **JSON array of objects** into the input.
2. Enter one or more **sort keys**, comma-separated — e.g. `age`, or `dept,-salary,name`.
   Use dots for nested fields and `-`/`+` to flip a single key's direction.
3. Pick the **default direction**, where **missing/null** values go, whether strings are
   **case-insensitive**, and the **indent** (0 to minify).
4. Read the sorted array. Everything runs locally in your browser — nothing is uploaded.

## FAQ

<!-- FAQ MUST be <details>/<summary> accordions. Keep the blank line inside each. -->

<details>
<summary>How is this different from sorting the keys of a JSON object?</summary>

This tool sorts the **elements** of an array — it changes the *order of the objects*, like
SQL's `ORDER BY`. Alphabetizing the **keys inside** each object (so `"zip"` comes after
`"city"`) is a different job; use a JSON key-sort tool for that. Here, the keys inside every
record stay exactly where they were.

</details>

<details>
<summary>Can I sort by more than one field, each in its own direction?</summary>

Yes. List the keys comma-separated and prefix any key with `-` for descending or `+` for
ascending — e.g. `dept,-salary,name` sorts by department ascending, then salary descending,
then name ascending. Keys without a prefix use the **default direction** you pick. Ties on
the first key are broken by the next, and the sort is **stable**, so equal rows keep their
original relative order.

</details>

<details>
<summary>What happens to rows where the sort field is missing or null?</summary>

A field that is absent or explicitly `null` is treated as **missing** and grouped together
at the **end** by default — switch **Missing / null values** to *first* to move them to the
top instead. This placement is **absolute**: missing rows stay on their chosen side even when
the key sorts descending, so they never mix into the middle of your data.

</details>

<details>
<summary>How are numbers, strings, and mixed types compared?</summary>

Numbers compare **numerically**, so `9` sorts before `10` (not lexically). Strings compare by
character; enable **Case-insensitive strings** to fold case so `Banana` sits next to `apple`
rather than ahead of all lowercase letters. If a field holds mixed types across rows, values
fall back to a stable type order (boolean, number, string, array, object) so the sort still
finishes deterministically.

</details>

<details>
<summary>Can I reach into nested objects or array elements?</summary>

Yes — use **dot-notation** in the key. `user.name` sorts by the `name` inside each row's
`user` object, and `tags.0` sorts by the first element of each row's `tags` array. If any
segment of the path doesn't exist for a row, that row counts as **missing** and follows the
missing/null placement rule.

</details>

## Limits & edge cases

- The input must be a **top-level JSON array**; a bare object or scalar is rejected with a
  clear error. Each element is expected to be an object you can sort by field.
- **Indent** is clamped to `0`–`8` spaces; `0` minifies to a single line, and any larger
  value is capped at 8.
- Comparison is **type-aware** but not locale-aware: strings sort by Unicode codepoint (with
  optional case-folding), and there is no numeric tolerance — `10` and `10.0` are equal as
  numbers but `"10"` (a string) is not.
- At least one **sort key** is required; an empty or all-blank `keys` value is an error.
- Everything runs in-browser via WebAssembly — the JSON you paste is never uploaded.

## Related tools

- [Adjacency Matrix Converter](https://gizza.ai/tools/adjacency-matrix-converter/): Convert a graph between edge list, adjacency matrix, and incidence matrix — directed or undirected, weighted or not. Free, private, runs in your browser.
- [Amazon Order Analyzer](https://gizza.ai/tools/amazon-order-analyzer/): Paste an Amazon order-history CSV export to summarize total spend by month, top items, and category breakdowns. Browser-only, private, with Markdown or JSON output.
- [Avro to JSON Converter](https://gizza.ai/tools/avro-to-json/): Decode Apache Avro Object Container Files (.avro / OCF) to JSON, NDJSON, or the embedded schema — no .avsc needed, free and private in your browser.
- [Reconcile bank statement and ledger CSVs](https://gizza.ai/tools/bank-statement-reconcile/): Match bank-statement CSV rows to ledger rows by date, signed amount, and fuzzy memo similarity, with unmatched and suggested matches.
- [Base64 ⇄ Base64url Converter](https://gizza.ai/tools/base64url-converter/): Convert standard Base64 to URL-safe Base64url and back in your browser — swaps +/ for -_, handles = padding, auto-detects direction. Free, private, no sign-up.
