Data Formats (JSON, YAML, TOML, XML, CSV) Module 4
Querying JSON: JSONPath, jq, JMESPath and SQL interview questions
Interview questions on “Querying JSON: JSONPath, jq, JMESPath and SQL”: warm-ups, then what each harder question tests and how a good answer starts.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher to mid
What does a JSONPath query return when nothing matches, and how do you tell that from a match whose value is null?
Answered in the lesson JSONPath (RFC 9535): selectors and segments
-
Fresher to mid
Why does $.items[?@.discount == null] miss the items that have no discount member?
Answered in the lesson JSONPath filters, comparisons and functions
-
Fresher to mid
jq, JMESPath or JSONPath: which can group orders by city and total them, and which can only select?
Answered in the lesson jq, JMESPath and SQL JSON paths compared
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Fresher to mid
A nightly job totals the values of $..price_paise in each partner's catalogue. One partner starts listing gift cards, and its total rises by exactly the gift cards' prices, with no error anywhere. Explain why, and how you would change the query and the job so that the next new kind of priced item cannot change a total unnoticed.
- What it tests
- Knowing that a descendant segment matches a name at every depth, writing explicit paths instead, and adding checks on normalized paths or a schema that flag new structures.
- First step
- Print the normalized path of every node the query returned. $..price_paise gave $['gift_cards'][0]['price_paise'] beside the four book prices, because .. applies the name selector to every node below the root. Total $.books[*].price_paise, the place you mean, and report any price that $..price_paise finds outside it.
- Follow-ups
-
- Why did nothing fail when the partner changed its structure?
- How would you detect the next new priced item automatically?
- When is a descendant segment the right tool?
From the lesson JSONPath (RFC 9535): selectors and segments
Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.Opening the model answers with your pass…
Model answers open with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so the model answers can’t be opened at the moment. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A contract test compares the nodelist of $.stock.* from a Python service with the one a Node.js service returns for the same document. The values always match as a set, but the test fails when stock is keyed by PIN codes such as 560001 and passes when it is keyed by city names. Explain the failure and fix the test.
- What it tests
- Knowing that RFC 9535 leaves the order of object members open, that JavaScript lists integer-like keys first, and comparing nodelists by normalized path instead of by position.
- First step
- Print both nodelists with their normalized paths and line them up. Python returned $['stock']['560001'] before $['stock']['411001'], in the document's order, while the Node.js service returned 411001 first; with city names both kept the document's order. Before you call either service wrong, read what section 2.3.2 of RFC 9535 says about the order of an object's members, and how JSON.parse orders keys that look like integers.
- Follow-ups
-
- Where does RFC 9535 fix the order of a nodelist?
- Would sorting both lists by value be enough?
- What should the contract say if the order of the stock matters?
From the lesson JSONPath (RFC 9535): selectors and segments
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A rules engine lets customers write JSONPath filters that route their orders, and its library evaluates filter text as JavaScript. Security asks you to move to an RFC 9535 library without breaking any customer's routing. How do you plan and prove the move?
- What it tests
- Seeing that evaluated filters are code injection, knowing where script-style filters and RFC 9535 differ, and migrating with a parser check, side-by-side runs and limits.
- First step
- Stop the risk before the migration: put every stored filter through an RFC 9535 parser today and list the ones it refuses, such as script expressions like [(@.length-1)] and JavaScript operators like === or .includes(). Those filters are the ones that cannot simply move; the rest can run on both libraries side by side.
- Follow-ups
-
- What do you do with the filters the new parser refuses?
- How do you show that the new library routes orders the same way?
- Which limits do you add for filters that customers write?
From the lesson JSONPath filters, comparisons and functions
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
The filter $.addresses[?match(@.pin, '[0-9]{6}')] keeps six-digit postal codes. A Python port written as re.match(r'\d{6}', pin) also accepts 5600012 and ५६०००१, codes the filter drops. Explain both acceptances and fix the port so that it agrees with the filter.
- What it tests
- Knowing that match() tests the whole string, that re.match anchors only at the start, that Python's \d matches any Unicode digit, and how to translate I-Regexp into Python.
- First step
- Run the old and the new check on both codes. re.match found 560001 at the start of 5600012 and stopped, because it anchors only at the start, while match() in JSONPath tests the whole string, as re.fullmatch does. And Python's \d matches every Unicode decimal digit, Devanagari ones included, while the filter's [0-9] means 0 to 9 only.
- Follow-ups
-
- Would adding re.ASCII to the original port be enough?
- How would you test that the port and the filter agree?
- What else differs between Python's re and I-Regexp?
From the lesson JSONPath filters, comparisons and functions
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
A deploy script picks one running server with aws ec2 describe-instances --output text and the query "Reservations[].Instances[?State.Name == 'running'].InstanceId | [0]". In a large account it sometimes prints several ids, and the next step breaks. Explain why, and make it print exactly one id every time.
- What it tests
- Reading JMESPath projections and pipes, knowing that the AWS CLI runs --query once per page with text output, and choosing output and filters that give one value.
- First step
- Run the expression on saved output first. Without a flatten, the projection gives one list per reservation, so | [0] returns the first reservation's list, which can hold several ids. Then read the AWS CLI guide: with --output text the query runs once on each page of results, so even a correct | [0] prints one id per page.
- Follow-ups
-
- Why does the same expression print one id with --output json?
- Where should the filtering on running servers happen, in the CLI or in the service?
- How would you make the script fail clearly when no server is running?
From the lesson jq, JMESPath and SQL JSON paths compared
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A jq step adds a computed total to each record of a ledger and passes every other member through. Downstream, the 20-digit record ids still match, but the totals of very large counters are wrong in their last digits. Why does jq keep one number exactly and not the other, and how do you make the pipeline safe?
- What it tests
- Knowing that jq 1.8 keeps the text of unchanged number literals but computes in double precision, and choosing ids as strings and exact arithmetic for large totals.
- First step
- Run both cases through jq: an unchanged literal such as 12345678901234567890 came out exactly, while .ref + 0 printed 12345678901234567000. jq keeps a number's original text only until it computes with it, and arithmetic is done in IEEE 754 double precision, exact for integers up to 2^53 − 1 only.
- Follow-ups
-
- Up to which value are jq totals exact?
- Where would you compute the totals instead?
- Why are the ids safe today, and what change would break them?
From the lesson jq, JMESPath and SQL JSON paths compared
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A report joins a table of branches to orders stored as JSON in SQLite with ON b.city = o.doc -> '$.city', and it matches no rows, although every city is in both tables. Explain the empty result, fix the join, and say which other comparisons in the report are at risk.
- What it tests
- Knowing that -> returns JSON text and ->> an SQL value, and checking types in joins, filters and sums over JSON columns.
- First step
- Select both sides next to each other: doc -> '$.city' gave "Pune", with the JSON quotes, while the branches table holds Pune, so no pair is equal. ->> returns the SQL text Pune. Change the join to b.city = o.doc ->> '$.city'.
- Follow-ups
-
- Why did the query not raise an error?
- What happens to numbers read with -> in a WHERE or a sum?
- How would you make such joins fast on a large table?
From the lesson jq, JMESPath and SQL JSON paths compared
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
All Data Formats (JSON, YAML, TOML, XML, CSV) interview questions · The Data Formats (JSON, YAML, TOML, XML, CSV) track