|
| 1 | +--- |
| 2 | +title: bag_keys |
| 3 | +description: 'This page explains how to use the bag_keys function in APL.' |
| 4 | +--- |
| 5 | + |
| 6 | +Use the `bag_keys` function in APL to extract the keys of a dynamic (bag) object as an array of strings. This is useful when you want to inspect or manipulate the structure of a dynamic field—such as JSON-like nested objects—without needing to know its exact schema in advance. |
| 7 | + |
| 8 | +Use `bag_keys` when you’re working with semi-structured data and want to: |
| 9 | + |
| 10 | +- Discover what properties are present in a dynamic object. |
| 11 | +- Iterate over the keys programmatically using other array functions. |
| 12 | +- Perform validation or debugging tasks to ensure all expected keys exist. |
| 13 | + |
| 14 | +This function is especially helpful in log analytics, observability pipelines, and security auditing, where dynamic properties are often collected from various services or devices. |
| 15 | + |
| 16 | +## For users of other query languages |
| 17 | + |
| 18 | +If you come from other query languages, this section explains how to adjust your existing queries to achieve the same results in APL. |
| 19 | + |
| 20 | +<AccordionGroup> |
| 21 | +<Accordion title="Splunk SPL users"> |
| 22 | + |
| 23 | +In Splunk SPL, you typically interact with JSON-like fields using the `spath` command or use `keys(_raw)` to retrieve field names. In APL, `bag_keys` serves a similar purpose by returning an array of keys from a dynamic object. |
| 24 | + |
| 25 | +<CodeGroup> |
| 26 | +```sql Splunk example |
| 27 | +| eval key_list=keys(data_field) |
| 28 | +```` |
| 29 | + |
| 30 | +```kusto APL equivalent |
| 31 | +datatable(data: dynamic) |
| 32 | +[ |
| 33 | + dynamic({ "ip": "127.0.0.1", "status": "200", "method": "GET" }) |
| 34 | +] |
| 35 | +| extend keys = bag_keys(data) |
| 36 | +``` |
| 37 | + |
| 38 | +</CodeGroup> |
| 39 | + |
| 40 | +</Accordion> |
| 41 | +<Accordion title="ANSI SQL users"> |
| 42 | + |
| 43 | +ANSI SQL doesn’t have native support for dynamic objects or JSON key introspection in the same way. However, some SQL dialects (like PostgreSQL or BigQuery) provide JSON-specific functions for extracting keys. `bag_keys` is the APL equivalent for dynamically introspecting JSON objects. |
| 44 | + |
| 45 | +<CodeGroup> |
| 46 | +```sql SQL example |
| 47 | +SELECT JSON_OBJECT_KEYS(data) FROM logs; |
| 48 | +``` |
| 49 | + |
| 50 | +```kusto APL equivalent |
| 51 | +datatable(data: dynamic) |
| 52 | +[ |
| 53 | + dynamic({ "ip": "127.0.0.1", "status": "200", "method": "GET" }) |
| 54 | +] |
| 55 | +| extend keys = bag_keys(data) |
| 56 | +``` |
| 57 | + |
| 58 | +</CodeGroup> |
| 59 | + |
| 60 | +</Accordion> |
| 61 | +</AccordionGroup> |
| 62 | + |
| 63 | +## Usage |
| 64 | + |
| 65 | +### Syntax |
| 66 | + |
| 67 | +```kusto |
| 68 | +bag_keys(bag) |
| 69 | +``` |
| 70 | + |
| 71 | +### Parameters |
| 72 | + |
| 73 | +| Name | Type | Description | |
| 74 | +| ----- | --------- | -------------------------------------------------- | |
| 75 | +| `bag` | `dynamic` | The dynamic object whose keys you want to extract. | |
| 76 | + |
| 77 | +### Returns |
| 78 | + |
| 79 | +An array of type `string[]` containing the names of the keys in the dynamic object. If the input is not a dynamic object, the function returns `null`. |
| 80 | + |
| 81 | +## Use case examples |
| 82 | + |
| 83 | +<Tabs> |
| 84 | +<Tab title="Log analysis"> |
| 85 | + |
| 86 | +Use `bag_keys` to audit dynamic metadata fields in HTTP logs where each record contains a nested object representing additional request attributes. |
| 87 | + |
| 88 | +**Query** |
| 89 | + |
| 90 | +```kusto |
| 91 | +['sample-http-logs'] |
| 92 | +| extend metadata = dynamic({ 'os': 'Windows', 'browser': 'Firefox', 'device': 'Desktop' }) |
| 93 | +| extend key_list = bag_keys(metadata) |
| 94 | +| project _time, uri, metadata, key_list |
| 95 | +``` |
| 96 | + |
| 97 | +[Run in Playground](https://play.axiom.co/axiom-play-qf1k/query?initForm=%7B%22apl%22%3A%22%5B'sample-http-logs'%5D%20%7C%20extend%20metadata%20%3D%20dynamic(%7B%20'os'%3A%20'Windows'%2C%20'browser'%3A%20'Firefox'%2C%20'device'%3A%20'Desktop'%20%7D)%20%7C%20extend%20key_list%20%3D%20bag_keys(metadata)%20%7C%20project%20_time%2C%20uri%2C%20metadata%2C%20key_list%22%7D) |
| 98 | + |
| 99 | +**Output** |
| 100 | + |
| 101 | +| _time | uri | metadata | key_list | |
| 102 | +| ------------------- | ------ | ------------------------------------------------ | ---------------------------- | |
| 103 | +| 2025-05-26 12:01:23 | /login | \{os: Windows, browser: Firefox, device: Desktop\} | [‘os’, ‘browser’, ‘device’] | |
| 104 | + |
| 105 | +This query inspects a simulated metadata object and returns the list of its keys, helping you debug inconsistencies or missing fields. |
| 106 | + |
| 107 | +</Tab> |
| 108 | +<Tab title="OpenTelemetry traces"> |
| 109 | + |
| 110 | +Use `bag_keys` to examine custom span attributes encoded as dynamic fields within OpenTelemetry trace events. |
| 111 | + |
| 112 | +**Query** |
| 113 | + |
| 114 | +```kusto |
| 115 | +['otel-demo-traces'] |
| 116 | +| extend attributes = dynamic({ 'user_id': 'abc123', 'feature_flag': 'enabled' }) |
| 117 | +| extend attribute_keys = bag_keys(attributes) |
| 118 | +| project _time, ['service.name'], kind, attributes, attribute_keys |
| 119 | +``` |
| 120 | + |
| 121 | +[Run in Playground](https://play.axiom.co/axiom-play-qf1k/query?initForm=%7B%22apl%22%3A%22%5B'otel-demo-traces'%5D%20%7C%20extend%20attributes%20%3D%20dynamic(%7B%20'user_id'%3A%20'abc123'%2C%20'feature_flag'%3A%20'enabled'%20%7D)%20%7C%20extend%20attribute_keys%20%3D%20bag_keys(attributes)%20%7C%20project%20_time%2C%20%5B'service.name'%5D%2C%20kind%2C%20attributes%2C%20attribute_keys%22%7D) |
| 122 | + |
| 123 | +**Output** |
| 124 | + |
| 125 | +| _time | ['service.name'] | kind | attributes | attribute_keys | |
| 126 | +| ------------------- | ----------------- | ------ | ------------------------------------------ | ------------------------------ | |
| 127 | +| 2025-05-26 13:14:01 | frontend | client | \{user_id: abc123, feature_flag: enabled\} | [‘user_id’, ‘feature_flag’] | |
| 128 | + |
| 129 | +This query inspects the custom span-level attributes and extracts their keys to verify attribute coverage or completeness. |
| 130 | + |
| 131 | +</Tab> |
| 132 | +<Tab title="Security logs"> |
| 133 | + |
| 134 | +Use `bag_keys` to list all security-related fields captured dynamically during request monitoring for auditing or compliance. |
| 135 | + |
| 136 | +**Query** |
| 137 | + |
| 138 | +```kusto |
| 139 | +['sample-http-logs'] |
| 140 | +| extend security_context = dynamic({ 'auth_status': 'success', 'role': 'admin', 'ip': '192.168.1.5' }) |
| 141 | +| extend fields = bag_keys(security_context) |
| 142 | +| project _time, status, ['geo.country'], security_context, fields |
| 143 | +``` |
| 144 | + |
| 145 | +[Run in Playground](https://play.axiom.co/axiom-play-qf1k/query?initForm=%7B%22apl%22%3A%22%5B'sample-http-logs'%5D%20%7C%20extend%20security_context%20%3D%20dynamic(%7B%20'auth_status'%3A%20'success'%2C%20'role'%3A%20'admin'%2C%20'ip'%3A%20'192.168.1.5'%20%7D)%20%7C%20extend%20fields%20%3D%20bag_keys(security_context)%20%7C%20project%20_time%2C%20status%2C%20%5B'geo.country'%5D%2C%20security_context%2C%20fields%22%7D) |
| 146 | + |
| 147 | +**Output** |
| 148 | + |
| 149 | +| _time | status | ['geo.country'] | security_context | fields | |
| 150 | +| ------------------- | ------ | ---------------- | ----------------------------------------------------- | ------------------------------- | |
| 151 | +| 2025-05-26 15:32:10 | 200 | US | \{auth_status: success, role: admin, ip: 192.168.1.5\} | [‘auth_status’, ‘role’, ‘ip’] | |
| 152 | + |
| 153 | +This helps you audit security metadata in requests and ensure key fields are present across records. |
| 154 | + |
| 155 | +</Tab> |
| 156 | +</Tabs> |
| 157 | + |
| 158 | +## List of related functions |
| 159 | + |
| 160 | +- [bag_pack](/apl/scalar-functions/array-functions/bag-pack): Converts a list of key-value pairs to a dynamic property bag. Use when you need to build a bag. |
| 161 | +- [bag_has_key](/apl/scalar-functions/array-functions/bag-has-key): Checks whether a dynamic property bag contains a specific key. |
0 commit comments