diff --git a/pkg/yqlib/doc/usage/recipes.md b/pkg/yqlib/doc/usage/recipes.md index 9e75c425..dc747f20 100644 --- a/pkg/yqlib/doc/usage/recipes.md +++ b/pkg/yqlib/doc/usage/recipes.md @@ -59,6 +59,44 @@ will output - The expression `. + 1` increments the numBuckets counter. - See the [assign](https://mikefarah.gitbook.io/yq/operators/assign-update) and [add](https://mikefarah.gitbook.io/yq/operators/add) operators for more information. +## Deeply prune a tree +Say we are only interested in child1 and child2, and want to filter everything else out. + +Given a sample.yml file of: +```yaml +parentA: + - bob +parentB: + child1: i am child1 + child3: hiya +parentC: + childX: cool + child2: me child2 +``` +then +```bash +yq '( + .. | # recurse through all the nodes + select(has("child1") or has("child2")) | # match parents that have either child1 or child2 + (.child1, .child2) | # select those children + select(.) # filter out nulls +) as $i ireduce({}; # using that set of nodes, create a new result map + setpath($i | path; $i) # and put in each node, using its original path +)' sample.yml +``` +will output +```yaml +parentB: + child1: i am child1 +parentC: + child2: me child2 +``` + +### Explanation: +- Find all the matching child1 and child2 nodes +- Using ireduce, create a new map using just those nodes +- Set each node into the new map using its original path + ## Multiple or complex updates to items in an array We have an array and we want to _update_ the elements with a particular name in reference to its type. diff --git a/pkg/yqlib/recipes_test.go b/pkg/yqlib/recipes_test.go index f5167ecf..40dd4c63 100644 --- a/pkg/yqlib/recipes_test.go +++ b/pkg/yqlib/recipes_test.go @@ -14,6 +14,15 @@ var nestedBashEnvScript = `.. |( ( select(kind == "seq") | (path | join("_")) + "=(" + (map("'" + . + "'") | join(",")) + ")") )` +var deepPruneExpression = `( + .. | # recurse through all the nodes + select(has("child1") or has("child2")) | # match parents that have either child1 or child2 + (.child1, .child2) | # select those children + select(.) # filter out nulls +) as $i ireduce({}; # using that set of nodes, create a new result map + setpath($i | path; $i) # and put in each node, using its original path +)` + var recipes = []expressionScenario{ { description: "Find items in an array", @@ -46,6 +55,20 @@ var recipes = []expressionScenario{ "D0, P[], (!!seq)::[{name: Foo, numBuckets: 1}, {name: Bar, numBuckets: 0}]\n", }, }, + { + description: "Deeply prune a tree", + subdescription: "Say we are only interested in child1 and child2, and want to filter everything else out.", + document: `{parentA: [bob],parentB: {child1: i am child1, child3: hiya},parentC: {childX: "cool",child2: me child2}}`, + expression: deepPruneExpression, + explanation: []string{ + "Find all the matching child1 and child2 nodes", + "Using ireduce, create a new map using just those nodes", + "Set each node into the new map using its original path", + }, + expected: []string{ + "D0, P[], (!!map)::parentB:\n child1: i am child1\nparentC:\n child2: me child2\n", + }, + }, { description: "Multiple or complex updates to items in an array", subdescription: "We have an array and we want to _update_ the elements with a particular name in reference to its type.",