{"id":15390259,"url":"https://github.com/gajus/unnest","last_synced_at":"2025-10-05T01:56:40.092Z","repository":{"id":66001251,"uuid":"155959604","full_name":"gajus/unnest","owner":"gajus","description":"Creates a cartesian product of properties identified using value pointers.","archived":false,"fork":false,"pushed_at":"2019-01-17T20:02:48.000Z","size":30,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-26T13:32:24.774Z","etag":null,"topics":["array","cartesian","declarative","template"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gajus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-11-03T07:12:05.000Z","updated_at":"2021-02-05T10:50:52.000Z","dependencies_parsed_at":"2023-02-27T00:30:21.058Z","dependency_job_id":null,"html_url":"https://github.com/gajus/unnest","commit_stats":{"total_commits":21,"total_committers":1,"mean_commits":21.0,"dds":0.0,"last_synced_commit":"4455695a5020d831927f47dad84edcee73a96aea"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/gajus/unnest","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gajus%2Funnest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gajus%2Funnest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gajus%2Funnest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gajus%2Funnest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gajus","download_url":"https://codeload.github.com/gajus/unnest/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gajus%2Funnest/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278399689,"owners_count":25980332,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["array","cartesian","declarative","template"],"created_at":"2024-10-01T15:05:08.385Z","updated_at":"2025-10-05T01:56:40.075Z","avatar_url":"https://github.com/gajus.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Unnest\n\n[![Travis build status](http://img.shields.io/travis/gajus/unnest/master.svg?style=flat-square)](https://travis-ci.org/gajus/unnest)\n[![Coveralls](https://img.shields.io/coveralls/gajus/unnest.svg?style=flat-square)](https://coveralls.io/github/gajus/unnest)\n[![NPM version](http://img.shields.io/npm/v/unnest.svg?style=flat-square)](https://www.npmjs.org/package/unnest)\n[![Canonical Code Style](https://img.shields.io/badge/code%20style-canonical-blue.svg?style=flat-square)](https://github.com/gajus/canonical)\n[![Twitter Follow](https://img.shields.io/twitter/follow/kuizinas.svg?style=social\u0026label=Follow)](https://twitter.com/kuizinas)\n\nCreates a cartesian product of all properties identified using value pointers.\n\n## API\n\n```js\n/**\n * @param {Object} tree A hierarchical data structure.\n * @returns {Array} A cartesian product of all values identified using value-pointers in the input object.\n */\nunnest(tree);\n\n```\n\n### Value-pointer\n\nIn the context of Unnest, value-pointer refers to an object property whose key begins with `@`, e.g.\n\n```js\n{\n  '@foo': {\n    name: 'bar'\n  }\n}\n\n```\n\n`@foo` is a value-pointer.\n\nData pointers are used to identify all members that are used to create the cartesian product.\n\n## Use case\n\nUnnest solves the problem of translating hierarchical dataset into a collection of atomic data records. This is a common requirement when extracting information from a hierarchical document (e.g. HTML) with intent to store it.\n\n### Example\n\nTo illustrate an example use case, consider an HTML document that describes event locations, dates and times:\n\n```html\n\u003cul\u003e\n  \u003cli class='location'\u003e\n    \u003ch1\u003efoo0\u003c/h1\u003e\n\n    \u003col\u003e\n      \u003cli class='date'\u003e\n        \u003ch2\u003ebar0\u003c/h2\u003e\n\n        \u003col\u003e\n          \u003cli class='time'\u003ebaz0\u003c/li\u003e\n          \u003cli class='time'\u003ebaz1\u003c/li\u003e\n        \u003c/ol\u003e\n      \u003c/li\u003e\n      \u003cli class='date'\u003e\n        \u003ch2\u003ebar2\u003c/h2\u003e\n\n        \u003col\u003e\n          \u003cli class='time'\u003ebaz2\u003c/li\u003e\n          \u003cli class='time'\u003ebaz3\u003c/li\u003e\n        \u003c/ol\u003e\n      \u003c/li\u003e\n    \u003c/ol\u003e\n  \u003c/li\u003e\n\u003cul\u003e\n\n```\n\nWe want to extract location, date and time information into a collection of objects that each describe all attributes of the event, i.e. The desired result is a cartesian product of all 3 variables (location, date and time):\n\n```json\n[\n  {\n    \"date\": \"bar0\",\n    \"location\": \"foo\",\n    \"time\": \"baz0\"\n  },\n  {\n    \"date\": \"bar0\",\n    \"location\": \"foo\",\n    \"time\": \"baz1\"\n  },\n  {\n    \"date\": \"bar1\",\n    \"location\": \"foo\",\n    \"time\": \"baz2\"\n  },\n  {\n    \"date\": \"bar1\",\n    \"location\": \"foo\",\n    \"time\": \"baz3\"\n  }\n]\n\n```\n\nWe can extract the subject data from the document using [Surgeon](https://github.com/gajus/surgeon). Surgeon uses declarative instructions to extract information out of a HTML document, e.g.\n\n```yaml\n- sm .location\n- '@location': so h1 | rdtc\n  children:\n    - sm .date\n    - '@date': so h2 | rdtc\n      children:\n        - '@time': sm .time | rdtc\n\n```\n\nThe result is a hierarchical object describing the relevant variables contained in the HTML document:\n\n```json\n[\n  {\n    \"@location\": \"foo0\",\n    \"children\": [\n      {\n        \"@date\": \"bar0\",\n        \"children\": [\n          {\n            \"@time\": \"baz0\"\n          },\n          {\n            \"@time\": \"baz1\"\n          }\n        ]\n      },\n      {\n        \"@date\": \"bar1\",\n        \"children\": [\n          {\n            \"@time\": \"baz2\"\n          },\n          {\n            \"@time\": \"baz3\"\n          }\n        ]\n      }\n    ]\n  }\n]\n\n```\n\nTo get a cartesian product of all the variables, we need to iterate the tree data structure:\n\n```js\nconst locations = input;\n\nconst result = {};\n\nfor (const locationDatum of locations) {\n  for (const dateDatum of locationDatum.children) {\n    for (const timeDatum of dateDatum.children) {\n      result.push({\n        date: dateDatum['@date'],\n        location: locationDatum['@location']\n        time: timeDatum['@time']\n      });\n    }\n  }\n}\n\n```\n\nUnnest replaces the last step:\n\n```js\nimport unnest from 'unnest';\n\nunnest(input);\n\n// [\n//   {\n//     \"@date\": \"bar0\",\n//     \"@location\": \"foo\",\n//     \"@time\": \"baz0\"\n//   },\n//   {\n//     \"@date\": \"bar0\",\n//     \"@location\": \"foo\",\n//     \"@time\": \"baz1\"\n//   },\n//   {\n//     \"@date\": \"bar1\",\n//     \"@location\": \"foo\",\n//     \"@time\": \"baz2\"\n//   },\n//   {\n//     \"@date\": \"bar1\",\n//     \"@location\": \"foo\",\n//     \"@time\": \"baz3\"\n//   }\n// ]\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgajus%2Funnest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgajus%2Funnest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgajus%2Funnest/lists"}