Better merge array by key example

This commit is contained in:
Mike Farah 2021-11-29 20:46:12 +11:00
parent 8c5d1e0252
commit 51e946e6ff
2 changed files with 16 additions and 12 deletions

View File

@ -234,11 +234,8 @@ will output
``` ```
## Merge arrays of objects together, matching on a key ## Merge arrays of objects together, matching on a key
It's a complex command, the trickyness comes from needing to have the right context in the expressions. There are two parts of the complex expression. The first part is doing the hard work, it creates a map from the arrays keyed by '.a',
First we save the second array into a variable '$two' which lets us reference it later. so that there are no duplicates. The second half converts that map back to an array.
We then need to update the first array. We will use the relative update (|=) because we need to update relative to the current element of the array in the LHS in the RHS expression.
We set the current element of the first array as $cur. Now we multiply (merge) $cur with the matching entry in $two, by passing $two through a select filter.
Given a sample.yml file of: Given a sample.yml file of:
```yaml ```yaml
@ -260,7 +257,10 @@ And another sample another.yml file of:
``` ```
then then
```bash ```bash
yq eval-all '(select(fi==1) | .[]) as $two | select(fi==0) | .[] |= (. as $cur | $cur * ($two | select(.a == $cur.a)))' sample.yml another.yml yq eval-all '
((.[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap
| ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value)
' sample.yml another.yml
``` ```
will output will output
```yaml ```yaml
@ -271,6 +271,8 @@ will output
- a: banana - a: banana
b: bananaB b: bananaB
c: bananaC c: bananaC
- a: dingo
c: dingoC
``` ```
## Merge to prefix an element ## Merge to prefix an element

View File

@ -29,10 +29,12 @@ var mergeArrayWithAnchors = `sample:
- <<: *a - <<: *a
` `
var mergeArraysObjectKeysText = `It's a complex command, the trickyness comes from needing to have the right context in the expressions. var mergeArraysObjectKeysText = `There are two parts of the complex expression. The first part is doing the hard work, it creates a map from the arrays keyed by '.a',
First we save the second array into a variable '$two' which lets us reference it later. so that there are no duplicates. The second half converts that map back to an array.`
We then need to update the first array. We will use the relative update (|=) because we need to update relative to the current element of the array in the LHS in the RHS expression.
We set the current element of the first array as $cur. Now we multiply (merge) $cur with the matching entry in $two, by passing $two through a select filter. var mergeExpression = `
((.[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap
| ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value)
` `
var docWithHeader = `# here var docWithHeader = `# here
@ -373,9 +375,9 @@ var multiplyOperatorScenarios = []expressionScenario{
subdescription: mergeArraysObjectKeysText, subdescription: mergeArraysObjectKeysText,
document: `[{a: apple, b: appleB}, {a: kiwi, b: kiwiB}, {a: banana, b: bananaB}]`, document: `[{a: apple, b: appleB}, {a: kiwi, b: kiwiB}, {a: banana, b: bananaB}]`,
document2: `[{a: banana, c: bananaC}, {a: apple, b: appleB2}, {a: dingo, c: dingoC}]`, document2: `[{a: banana, c: bananaC}, {a: apple, b: appleB2}, {a: dingo, c: dingoC}]`,
expression: `(select(fi==1) | .[]) as $two | select(fi==0) | .[] |= (. as $cur | $cur * ($two | select(.a == $cur.a)))`, expression: mergeExpression,
expected: []string{ expected: []string{
"D0, P[], (doc)::[{a: apple, b: appleB2}, {a: kiwi, b: kiwiB}, {a: banana, b: bananaB, c: bananaC}]\n", "D0, P[], (!!seq)::- {a: apple, b: appleB2}\n- {a: kiwi, b: kiwiB}\n- {a: banana, b: bananaB, c: bananaC}\n- {a: dingo, c: dingoC}\n",
}, },
}, },
{ {