Mutable Table Aggregations
Reported by candidates from Notion's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
Notion's April 2026 OA looks like a database problem, but it reduces to one thing: keeping count, sum, and max correct while rows change underneath you. No fancy algorithm. You maintain per-table state with hash maps, and the real work is the max after an UPDATE or DELETE. If you've got an invite in your inbox, this is a design-flavored hash-table question that punishes sloppy bookkeeping. StealthCoder sits invisibly on your screen as a safety net if you blank during the live OA, but the logic below is small enough to hold in your head.
The problem
Maintain integer-valued rows across independent tables. Process these operations: ["ADD", tableId, rowId, value] inserts a new row. ["UPDATE", tableId, rowId, value] replaces an existing row's value. ["DELETE", tableId, rowId] removes an existing row. ["QUERY", tableId] returns count|sum|average|max for that table. Format a non-empty table's average with exactly two digits after the decimal point. For an empty table, return 0|0|0.00|NULL. Return the values produced by QUERY operations in order. Function runTableAggregations(operations: String[][]) → String[] Examples Example 1 operations = [["ADD","docs","r1","10"],["ADD","docs","r2","20"],["QUERY","docs"],["UPDATE","docs","r1","40"],["QUERY","docs"],["DELETE","docs","r2"],["QUERY","docs"]] return = ["2|30|15.00|20","2|60|30.00|40","1|40|40.00|40"] The first query aggregates two rows. Updating r1 changes sum, average, and maximum; deleting r2 leaves one row. Constraints 1 <= operations.length <= 20000. Table and row IDs are non-empty ASCII strings containing neither | nor whitespace. Values are decimal integers in [-10^9, 10^9]. An ADD row ID is absent from that table; an UPDATE or DELETE row ID is present. Every table contains at most 10000 rows, and every sum fits a signed 64-bit integer.
Reported by candidates. Source: FastPrep
Pattern and pitfall
Keep a map from tableId to a map of rowId to value. Count is the map size. Sum is a running long you adjust on ADD (plus value), UPDATE (plus new minus old), and DELETE (minus old). The trap is max. A running max breaks the moment you delete or lower the current maximum. With at most 10000 rows per table and 20000 operations, you can just scan the table's values on QUERY and skip all the cleverness. If you want it faster, use a TreeMap of value to frequency, or a heap with lazy deletion. Other pitfalls: average must print exactly two decimals, so use fixed-point formatting, and watch negative values and 64-bit sums. An empty table returns 0|0|0.00|NULL, so handle that case first. If the live OA has you blanking on the formatting or the max edge case, StealthCoder is the hedge.
StealthCoder is the hedge for the one pattern you didn't drill. It runs invisibly during the screen share.
You can drill Mutable Table Aggregations 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. If you're reading this with an OA window open, you're who this was built for.
Get StealthCoderRelated leaked OAs
You've seen the question.
Make sure you actually pass Notion's OA.
Notion reuses patterns across OAs. If you're reading this with an OA window open, you're who this was built for. Works on HackerRank, CodeSignal, CoderPad, and Karat.
Mutable Table Aggregations FAQ
What's the actual trick in this Notion OA problem?+
Maintain a hash map of tables to rows and update count and sum incrementally. The only hard part is max after UPDATE or DELETE. A running max goes stale, so rescan the table or use a sorted frequency map.
Is a brute-force scan on QUERY fast enough?+
Probably. Each table holds at most 10000 rows and there are at most 20000 operations, so worst case is around 200 million simple steps if every operation is a query on a full table. A sorted frequency map or heap with lazy deletion removes the risk.
How do I format the average correctly?+
Compute sum divided by count as a double and print with exactly two decimals, like a fixed-format printf of %.2f. Watch negative sums and rounding. For an empty table, skip the math and return the literal 0|0|0.00|NULL.
What edge cases should I test before submitting?+
Delete the current max, update the max downward, update a non-max row above the max, empty a table then query it, and use negative values. Also test two tables with the same rowId, since row IDs are only unique within a table.
How do I prepare for this in 48 hours?+
Write the solution once with nested hash maps and a rescan for max. Then try the sorted frequency map version. Practice the output format by hand against Example 1. It's a bookkeeping problem, not an algorithm problem, so careful state updates matter most.