Reported July 2025
Zipdesign

In-Memory Database with TTL and Historical Queries

Reported by candidates from Zip's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.

Get StealthCoderRuns invisibly during the live Zip OA. Under 2s to a working solution.
Founder's read

Zip reported this one in July 2025, and the detail that matters is in the SET_TTL rule: a field is active from time through times strictly less than time + ttl. That off-by-one decides half your test cases. The problem is an in-memory database built in four layers: field operations, SCAN and SCAN_PREFIX, expiration, and GET_WHEN historical lookup. It's a design problem, not an algorithm puzzle. With at most 200 queries, nothing needs to be clever. You just need the right data model. If you blank on the version history idea, StealthCoder is a quiet safety net during the live OA.

The problem

Implement an in-memory database that stores string values by record key and field. Process the queries in order and return one string for each query. This practice interface combines the four progressively unlocked levels reported in a Zip backend technical interview: field operations, filtered scans, expiration, and historical lookup.
Every query starts with an operation name and a strictly increasing integer timestamp written as a string. Supported operations are:
["SET", time, key, field, value]: create or replace a field; return "".
["GET", time, key, field]: return its current value, or "" if absent.
["DELETE", time, key, field]: remove a currently active field; return "true" when removed and "false" otherwise.
["SCAN", time, key]: list active fields of the record in lexicographic field order as field(value), joined by ", ". Return "" for no fields.
["SCAN_PREFIX", time, key, prefix]: use the same format, keeping only fields whose names begin with prefix.
["SET_TTL", time, key, field, value, ttl]: set a field that is active from time through times strictly less than time + ttl; return "".
["GET_WHEN", time, key, field, at]: return the value that was active at past timestamp at, or "" if none was active then. The lookup itself does not change the database.
A later SET or SET_TTL replaces the previous version immediately. Expiration and deletion leave earlier versions available to GET_WHEN. The time of a GET_WHEN query may be later than its at argument.

Function
processQueries(queries: String[][]) → String[]

Examples
Example 1
queries = [["SET","1","user","name","Ada"],["SET","2","user","city","SF"],["GET","3","user","name"],["SCAN_PREFIX","4","user","c"],["SET","5","user","name","Bea"],["SCAN","6","user"],["DELETE","7","user","city"],["GET","8","user","city"],["DELETE","9","user","city"]]
return = ["","","Ada","city(SF)","","city(SF), name(Bea)","true","","false"]
The update replaces the name at time 5. The first delete removes the city; the second finds no active city.
Example 2
queries = [["SET_TTL","1","r","status","open","3"],["GET","3","r","status"],["GET","4","r","status"],["SET","5","r","status","closed"],["GET_WHEN","6","r","status","2"],["GET_WHEN","7","r","status","4"],["GET_WHEN","8","r","status","5"],["SCAN","9","r"]]
return = ["","open","","","open","","closed","status(closed)"]
The first value expires exactly at time 4. Historical queries recover time 2 and correctly leave time 4 empty.

Constraints
1 <= queries.length <= 200.
Query timestamps are positive and strictly increasing. Every at is nonnegative and no greater than its query's timestamp.
Keys, fields, prefixes, and values are nonempty strings of at most 30 letters or digits; values never contain parentheses or commas.
Each ttl is a positive integer. Timestamps and TTLs are at most 10^9.
Every query has exactly the arguments shown for its operation.

Reported by candidates. Source: FastPrep

Pattern and pitfall

The trick is to never overwrite. Store every field as a list of versions, each with start time, end time (or infinity), and value. SET and SET_TTL close the previous active version at the new time, then append a new one. DELETE closes the active version at the current time and returns true only if one was active. GET and SCAN check which version is active at the query time. GET_WHEN checks which version covered the at timestamp. Active means start <= t < end. Use that same check everywhere. The pitfall is expiry: a TTL version that has lapsed is not active, so DELETE must return false for it. Another trap is a replaced version, which must end at the replacement time, not at its original TTL end if that's later. Sort field names lexicographically for SCAN. With 200 queries, scanning linearly is fine. StealthCoder is there if the versioning logic tangles mid-assessment.

Drill it cold or hedge it with StealthCoder. Either way, don't walk into the OA hoping you remember the trick.

If this hits your live OA

You can drill In-Memory Database with TTL and Historical Queries cold, or you can hedge it. StealthCoder runs invisibly during screen share and surfaces a working solution in under 2 seconds. The proctor sees the IDE. They don't see what's behind it. Made for the candidate who got the OA invite this morning and has 72 hours, not six months.

Get StealthCoder

Related leaked OAs

⏵ The honest play

You've seen the question. Make sure you actually pass Zip's OA.

Zip reuses patterns across OAs. Made for the candidate who got the OA invite this morning and has 72 hours, not six months. Works on HackerRank, CodeSignal, CoderPad, and Karat.

In-Memory Database with TTL and Historical Queries FAQ

What's the trick in the Zip in-memory database problem?+

Keep a version history per key and field instead of a single value. Each version has a start time, an end time, and a value. Every operation then becomes one question: which version covers time t. That single check powers GET, SCAN, DELETE and GET_WHEN.

How does TTL expiration work exactly?+

A SET_TTL field is active for times t where time <= t < time + ttl. In Example 2, TTL 3 set at time 1 is readable at time 3 and gone at time 4. Store the end as time + ttl and compare with strictly less than.

Does GET_WHEN see deleted or expired values?+

Yes. Deletion and expiration only close a version's end time, they don't erase it. GET_WHEN looks for a version whose interval contains the at timestamp. If at falls after expiry or before any SET, return an empty string.

How hard is this really, given 200 queries?+

Logic-heavy, not performance-heavy. With 200 queries, linear scans over version lists are fine, so skip heaps and trees. The difficulty is getting boundary conditions right across four layered features, especially replacement and expiry interacting on the same field.

How do I prepare for this in 48 hours?+

Write the version-list class once, then hand-run both examples against it. Test edge cases: SET replacing a TTL field early, DELETE on an expired field, SCAN_PREFIX with no matches, and GET_WHEN where the query time is later than at. Check the output format of SCAN carefully.

Problem reported by candidates from a real Online Assessment. Sourced from a publicly-available candidate-aggregated repository. Not affiliated with Zip.

OA at Zip?
Invisible during screen share
Get it