Reason About Recursive Key Search in Nested JSON
MongoDBSoftware Engineer · Technical ScreenLast updated
Implement a recursive search function to extract all values associated with a given key from deeply nested JSON documents containing arbitrary combinations of dictionaries and lists.
Problem Statement
In document databases like MongoDB, documents can contain arbitrarily nested structures consisting of nested objects (maps/dictionaries) and arrays (lists).
Write a function find_values(document, target_key) that recursively traverses a nested JSON document and collects all values associated with target_key.
Your implementation must adhere to the following rules:
- If an object contains
target_key, append its associated value to the results. If that associated value is itself a nested dictionary or list, you should still search inside it for further occurrences oftarget_key. - If a list/array is encountered, recursively inspect each element in order.
- If the target key appears multiple times across different branches or nesting depths, preserve pre-order depth-first traversal order in the returned list.
- If the key is not present anywhere in the document, return an empty list
[]. - Keys are case-sensitive.
Function Signature
from typing import Any
def find_values(document: Any, target_key: str) -> list[Any]:
pass
Examples
Example 1
input_doc = {
"user": {
"id": 101,
"name": "Alice",
"metadata": {
"id": "sub_101",
"status": "active"
}
},
"tags": ["admin", "staff"],
"id": 999
}
target = "id"
# Output:
# [101, "sub_101", 999] (or [999, 101, "sub_101"] depending on dict key ordering; pre-order traversal of keys)
Explanation: The key "id" appears at the root level (999), under "user" (101), and under "metadata" ("sub_101"). All three values are collected.
Example 2
input_doc = {
"item": {
"item": {
"name": "Widget"
}
}
}
target = "item"
# Output:
# [{"item": {"name": "Widget"}}, {"name": "Widget"}]
Explanation: The outer "item" maps to a dict that itself contains another "item" key. Both values are captured.
Constraints
- The document structure contains only valid JSON types:
dict,list,str,int,float,bool, andNone. - Nesting depth will not exceed 500 levels.
- Total number of keys and array elements across the document is at most
10^5.
Edge Cases
- The target value itself is
Noneor an empty container ({}or[]). - The root input is an empty dictionary, an empty list, or a primitive value.
- Multiple identical values or duplicated keys across branches.
Hints
Hint 1
Identify your base cases first: primitive types (strings, numbers, booleans, and None) cannot be traversed further and should immediately return.
Hint 2
When traversing a dictionary, remember that finding a match does not mean you stop searching inside that branch if the matched value is itself a container.
Hint 3
Use a helper function that passes an accumulator list (or use a generator/yield pattern) to avoid repeated list concatenation overhead during recursion.
Follow-up questions
- How would you modify this solution to return the full JSON path (e.g., 'user.metadata.id' or 'items[2].id') for each match?
- If the document can contain circular references, how would you adapt your traversal to prevent infinite loops while still supporting JSON documents?
- How would you rewrite this iteratively to avoid call-stack overflow in environments with strict recursion limits?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.