From 46d1d6825f7b7bb968d9d24548eb7b1b90da9d80 Mon Sep 17 00:00:00 2001 From: Rob Ferguson Date: Wed, 24 Nov 2021 08:56:21 -0600 Subject: [PATCH 01/11] Include version query for tools --- scripts/devtools.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/devtools.sh b/scripts/devtools.sh index 4e7126c2..528f317f 100755 --- a/scripts/devtools.sh +++ b/scripts/devtools.sh @@ -1,5 +1,5 @@ #!/bin/sh set -ex -go mod download golang.org/x/tools +go mod download golang.org/x/tools@latest wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.37.1 wget -O- -nv https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s v2.9.1 From 3e82171f18dbfe64b3813d86b61d4b3f7329308e Mon Sep 17 00:00:00 2001 From: Paul S Date: Wed, 24 Nov 2021 14:15:41 +0000 Subject: [PATCH 02/11] Clean up errored file? Probably a leftover of shell testing? --- 1 | 1 - 1 file changed, 1 deletion(-) delete mode 100644 1 diff --git a/1 b/1 deleted file mode 100644 index 377f7756..00000000 --- a/1 +++ /dev/null @@ -1 +0,0 @@ -Error: cannot pass files in when using null-input flag From 15d7c9e118b4f7f1adc6b190a518f5823c82ed78 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Thu, 25 Nov 2021 10:24:51 +0100 Subject: [PATCH 03/11] enable misspell linter --- .golangci.yml | 1 + cmd/utils.go | 2 +- pkg/yqlib/expression_postfix.go | 2 +- pkg/yqlib/file_utils.go | 2 +- pkg/yqlib/operator_equals_test.go | 2 +- pkg/yqlib/operator_load.go | 2 +- pkg/yqlib/operator_multiply.go | 2 +- pkg/yqlib/operator_strings_test.go | 2 +- pkg/yqlib/operator_traverse_path.go | 4 ++-- pkg/yqlib/utils.go | 2 +- 10 files changed, 11 insertions(+), 10 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index ae6360a8..ae8999ed 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -6,6 +6,7 @@ linters: - gofmt - goimports - gosec + - misspell issues: exclude-rules: - linters: diff --git a/cmd/utils.go b/cmd/utils.go index 80a2b295..483ea426 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -25,7 +25,7 @@ func initCommand(cmd *cobra.Command, args []string) (firstFileIndex int, err err firstFileIndex = 1 } - // backwards compatibilty + // backwards compatibility if outputToJSON { outputFormat = "json" } diff --git a/pkg/yqlib/expression_postfix.go b/pkg/yqlib/expression_postfix.go index e237f888..f9938680 100644 --- a/pkg/yqlib/expression_postfix.go +++ b/pkg/yqlib/expression_postfix.go @@ -68,7 +68,7 @@ func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Ope } // now we should have [ as the last element on the opStack, get rid of it opStack = opStack[0 : len(opStack)-1] - log.Debugf("deleteing open bracket from opstack") + log.Debugf("deleting open bracket from opstack") //and append a collect to the result // hack - see if there's the optional traverse flag diff --git a/pkg/yqlib/file_utils.go b/pkg/yqlib/file_utils.go index 7668a8e1..7a423720 100644 --- a/pkg/yqlib/file_utils.go +++ b/pkg/yqlib/file_utils.go @@ -34,7 +34,7 @@ func tryRemoveFile(filename string) { // thanks https://stackoverflow.com/questions/21060945/simple-way-to-copy-a-file-in-golang func copyFileContents(src, dst string) (err error) { - // ignore CWE-22 gosec issue - that's more targetted for http based apps that run in a public directory, + // ignore CWE-22 gosec issue - that's more targeted for http based apps that run in a public directory, // and ensuring that it's not possible to give a path to a file outside thar directory. in, err := os.Open(src) // #nosec diff --git a/pkg/yqlib/operator_equals_test.go b/pkg/yqlib/operator_equals_test.go index 1064ebd3..69cd6e09 100644 --- a/pkg/yqlib/operator_equals_test.go +++ b/pkg/yqlib/operator_equals_test.go @@ -173,7 +173,7 @@ var equalsOperatorScenarios = []expressionScenario{ }, }, { - description: "Two non existant keys are equal", + description: "Two non existent keys are equal", document: "a: frog", expression: `select(.b == .c)`, expected: []string{ diff --git a/pkg/yqlib/operator_load.go b/pkg/yqlib/operator_load.go index 2c3be798..4741b09a 100644 --- a/pkg/yqlib/operator_load.go +++ b/pkg/yqlib/operator_load.go @@ -15,7 +15,7 @@ type loadPrefs struct { } func loadString(filename string) (*CandidateNode, error) { - // ignore CWE-22 gosec issue - that's more targetted for http based apps that run in a public directory, + // ignore CWE-22 gosec issue - that's more targeted for http based apps that run in a public directory, // and ensuring that it's not possible to give a path to a file outside that directory. filebytes, err := ioutil.ReadFile(filename) // #nosec diff --git a/pkg/yqlib/operator_multiply.go b/pkg/yqlib/operator_multiply.go index d7bec73d..a60f0287 100644 --- a/pkg/yqlib/operator_multiply.go +++ b/pkg/yqlib/operator_multiply.go @@ -42,7 +42,7 @@ func multiply(preferences multiplyPreferences) func(d *dataTreeNavigator, contex leadingContent, headComment, footComment := getComments(lhs, rhs) lhs.Node = unwrapDoc(lhs.Node) rhs.Node = unwrapDoc(rhs.Node) - log.Debugf("Multipling LHS: %v", lhs.Node.Tag) + log.Debugf("Multiplying LHS: %v", lhs.Node.Tag) log.Debugf("- RHS: %v", rhs.Node.Tag) if lhs.Node.Kind == yaml.MappingNode && rhs.Node.Kind == yaml.MappingNode || diff --git a/pkg/yqlib/operator_strings_test.go b/pkg/yqlib/operator_strings_test.go index f1218010..c94a2fc8 100644 --- a/pkg/yqlib/operator_strings_test.go +++ b/pkg/yqlib/operator_strings_test.go @@ -99,7 +99,7 @@ var stringsOperatorScenarios = []expressionScenario{ }, { description: "Test using regex", - subdescription: "Like jq'q equivalant, this works like match but only returns true/false instead of full match details", + subdescription: "Like jq'q equivalent, this works like match but only returns true/false instead of full match details", document: `["cat", "dog"]`, expression: `.[] | test("at")`, expected: []string{ diff --git a/pkg/yqlib/operator_traverse_path.go b/pkg/yqlib/operator_traverse_path.go index e02c388e..08c36e5b 100644 --- a/pkg/yqlib/operator_traverse_path.go +++ b/pkg/yqlib/operator_traverse_path.go @@ -42,7 +42,7 @@ func traverse(d *dataTreeNavigator, context Context, matchingNode *CandidateNode if value.Tag == "!!null" && operation.Value != "[]" { log.Debugf("Guessing kind") - // we must ahve added this automatically, lets guess what it should be now + // we must have added this automatically, lets guess what it should be now switch operation.Value.(type) { case int, int64: log.Debugf("probably an array") @@ -87,7 +87,7 @@ func traverseArrayOperator(d *dataTreeNavigator, context Context, expressionNode return Context{}, err } - // rhs is a collect expression that will yield indexes to retreive of the arrays + // rhs is a collect expression that will yield indexes to retrieve of the arrays rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs) diff --git a/pkg/yqlib/utils.go b/pkg/yqlib/utils.go index f992116e..aa514770 100644 --- a/pkg/yqlib/utils.go +++ b/pkg/yqlib/utils.go @@ -17,7 +17,7 @@ func readStream(filename string, leadingContentPreProcessing bool) (io.Reader, s if filename == "-" { reader = bufio.NewReader(os.Stdin) } else { - // ignore CWE-22 gosec issue - that's more targetted for http based apps that run in a public directory, + // ignore CWE-22 gosec issue - that's more targeted for http based apps that run in a public directory, // and ensuring that it's not possible to give a path to a file outside thar directory. file, err := os.Open(filename) // #nosec if err != nil { From cbb7fc91924290cb97f8c04b2aa188dd31216fa0 Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Fri, 26 Nov 2021 09:54:01 +1100 Subject: [PATCH 04/11] updated readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 26717799..7c12d6b4 100644 --- a/README.md +++ b/README.md @@ -220,6 +220,7 @@ Supported by @rmescandon (https://launchpad.net/~rmescandon/+archive/ubuntu/yq) - [Update yaml inplace](https://mikefarah.gitbook.io/yq/v/v4.x/commands/evaluate#flags) - [Complex expressions to select and update](https://mikefarah.gitbook.io/yq/operators/select#select-and-update-matching-values-in-map) - Keeps yaml formatting and comments when updating (though there are issues with whitespace) +- [Load content from other files](https://mikefarah.gitbook.io/yq/operators/load) - [Convert to/from json](https://mikefarah.gitbook.io/yq/v/v4.x/usage/convert) - [Convert to properties](https://mikefarah.gitbook.io/yq/v/v4.x/usage/properties) - [Pipe data in by using '-'](https://mikefarah.gitbook.io/yq/v/v4.x/commands/evaluate) From 8fdf6414c1036cbb5ceaff4a0a6101eb947b5259 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Fri, 26 Nov 2021 10:02:57 +0100 Subject: [PATCH 05/11] update Golangci version to v1.43.0 --- scripts/devtools.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/devtools.sh b/scripts/devtools.sh index 528f317f..89c895c3 100755 --- a/scripts/devtools.sh +++ b/scripts/devtools.sh @@ -1,5 +1,5 @@ #!/bin/sh set -ex go mod download golang.org/x/tools@latest -wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.37.1 +wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.43.0 wget -O- -nv https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s v2.9.1 From 8c5d1e02523dda42b0969a3507193c0ee602ec92 Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Fri, 26 Nov 2021 20:24:21 +1100 Subject: [PATCH 06/11] gci linter --- .golangci.yml | 1 + go.sum | 1 - pkg/yqlib/doc/equals.md | 2 +- pkg/yqlib/doc/string-operators.md | 2 +- pkg/yqlib/operator_add.go | 1 - pkg/yqlib/operator_comments.go | 2 -- pkg/yqlib/operator_multiply.go | 3 +-- pkg/yqlib/operator_subtract.go | 1 - 8 files changed, 4 insertions(+), 9 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index ae8999ed..7a9f27b7 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -3,6 +3,7 @@ run: linters: enable: - errorlint + - gci - gofmt - goimports - gosec diff --git a/go.sum b/go.sum index 4ccfbb19..513b09cc 100644 --- a/go.sum +++ b/go.sum @@ -471,7 +471,6 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/yqlib/doc/equals.md b/pkg/yqlib/doc/equals.md index d7129a79..17771963 100644 --- a/pkg/yqlib/doc/equals.md +++ b/pkg/yqlib/doc/equals.md @@ -108,7 +108,7 @@ will output a: frog ``` -## Two non existant keys are equal +## Two non existent keys are equal Given a sample.yml file of: ```yaml a: frog diff --git a/pkg/yqlib/doc/string-operators.md b/pkg/yqlib/doc/string-operators.md index dafe6f30..ec6ef53f 100644 --- a/pkg/yqlib/doc/string-operators.md +++ b/pkg/yqlib/doc/string-operators.md @@ -209,7 +209,7 @@ will output ``` ## Test using regex -Like jq'q equivalant, this works like match but only returns true/false instead of full match details +Like jq'q equivalent, this works like match but only returns true/false instead of full match details Given a sample.yml file of: ```yaml diff --git a/pkg/yqlib/operator_add.go b/pkg/yqlib/operator_add.go index 1473bbfc..0a141ab6 100644 --- a/pkg/yqlib/operator_add.go +++ b/pkg/yqlib/operator_add.go @@ -2,7 +2,6 @@ package yqlib import ( "fmt" - "strconv" yaml "gopkg.in/yaml.v3" diff --git a/pkg/yqlib/operator_comments.go b/pkg/yqlib/operator_comments.go index 9671bc50..ebc78b9d 100644 --- a/pkg/yqlib/operator_comments.go +++ b/pkg/yqlib/operator_comments.go @@ -1,8 +1,6 @@ package yqlib import ( - // "bufio" - // "bytes" "bufio" "bytes" "container/list" diff --git a/pkg/yqlib/operator_multiply.go b/pkg/yqlib/operator_multiply.go index a60f0287..ff0410e9 100644 --- a/pkg/yqlib/operator_multiply.go +++ b/pkg/yqlib/operator_multiply.go @@ -1,11 +1,10 @@ package yqlib import ( + "container/list" "fmt" "strconv" - "container/list" - "github.com/jinzhu/copier" yaml "gopkg.in/yaml.v3" ) diff --git a/pkg/yqlib/operator_subtract.go b/pkg/yqlib/operator_subtract.go index 6a74ab27..51d68cbf 100644 --- a/pkg/yqlib/operator_subtract.go +++ b/pkg/yqlib/operator_subtract.go @@ -2,7 +2,6 @@ package yqlib import ( "fmt" - "strconv" "gopkg.in/yaml.v3" From 51e946e6ff39e4ed9a3b5e3b76db74c2e7987b6d Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Mon, 29 Nov 2021 20:46:12 +1100 Subject: [PATCH 07/11] Better merge array by key example --- pkg/yqlib/doc/multiply-merge.md | 14 ++++++++------ pkg/yqlib/operator_multiply_test.go | 14 ++++++++------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/pkg/yqlib/doc/multiply-merge.md b/pkg/yqlib/doc/multiply-merge.md index ffc36b11..c70283b8 100644 --- a/pkg/yqlib/doc/multiply-merge.md +++ b/pkg/yqlib/doc/multiply-merge.md @@ -234,11 +234,8 @@ will output ``` ## 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. -First we save the second array into a variable '$two' which lets us reference it later. -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. - +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', +so that there are no duplicates. The second half converts that map back to an array. Given a sample.yml file of: ```yaml @@ -260,7 +257,10 @@ And another sample another.yml file of: ``` then ```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 ```yaml @@ -271,6 +271,8 @@ will output - a: banana b: bananaB c: bananaC +- a: dingo + c: dingoC ``` ## Merge to prefix an element diff --git a/pkg/yqlib/operator_multiply_test.go b/pkg/yqlib/operator_multiply_test.go index b1355075..39bdbf35 100644 --- a/pkg/yqlib/operator_multiply_test.go +++ b/pkg/yqlib/operator_multiply_test.go @@ -29,10 +29,12 @@ var mergeArrayWithAnchors = `sample: - <<: *a ` -var mergeArraysObjectKeysText = `It's a complex command, the trickyness comes from needing to have the right context in the expressions. -First we save the second array into a variable '$two' which lets us reference it later. -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 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', +so that there are no duplicates. The second half converts that map back to an array.` + +var mergeExpression = ` +((.[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap +| ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value) ` var docWithHeader = `# here @@ -373,9 +375,9 @@ var multiplyOperatorScenarios = []expressionScenario{ subdescription: mergeArraysObjectKeysText, 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}]`, - expression: `(select(fi==1) | .[]) as $two | select(fi==0) | .[] |= (. as $cur | $cur * ($two | select(.a == $cur.a)))`, + expression: mergeExpression, 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", }, }, { From 4c7c0b83aa0a377a67c60e848568cc0f425ebf90 Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Mon, 29 Nov 2021 20:53:36 +1100 Subject: [PATCH 08/11] Better merge array by key example --- pkg/yqlib/doc/multiply-merge.md | 6 ++++-- pkg/yqlib/operator_multiply_test.go | 8 +++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/pkg/yqlib/doc/multiply-merge.md b/pkg/yqlib/doc/multiply-merge.md index c70283b8..000c8536 100644 --- a/pkg/yqlib/doc/multiply-merge.md +++ b/pkg/yqlib/doc/multiply-merge.md @@ -237,6 +237,9 @@ will output 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', so that there are no duplicates. The second half converts that map back to an array. +To use this, you will need to update '.[]' to be the expression to your array (e.g. .my.array[]), and '.a' to be the key field of your array (e.g. '.name') + + Given a sample.yml file of: ```yaml - a: apple @@ -257,8 +260,7 @@ And another sample another.yml file of: ``` then ```bash -yq eval-all ' -((.[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap +yq eval-all '((.[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap | ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value) ' sample.yml another.yml ``` diff --git a/pkg/yqlib/operator_multiply_test.go b/pkg/yqlib/operator_multiply_test.go index 39bdbf35..d95a6152 100644 --- a/pkg/yqlib/operator_multiply_test.go +++ b/pkg/yqlib/operator_multiply_test.go @@ -30,10 +30,12 @@ var mergeArrayWithAnchors = `sample: ` 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', -so that there are no duplicates. The second half converts that map back to an array.` +so that there are no duplicates. The second half converts that map back to an array. -var mergeExpression = ` -((.[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap +To use this, you will need to update '.[]' to be the expression to your array (e.g. .my.array[]), and '.a' to be the key field of your array (e.g. '.name') +` + +var mergeExpression = `((.[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap | ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value) ` From 418bd1a8067fd3319499355261f16fa2fa930706 Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Mon, 29 Nov 2021 20:56:04 +1100 Subject: [PATCH 09/11] Added credit for merge by array example --- merge-array-by-key.sh | 8 ++++++++ pkg/yqlib/doc/multiply-merge.md | 2 ++ pkg/yqlib/operator_multiply_test.go | 2 ++ 3 files changed, 12 insertions(+) create mode 100755 merge-array-by-key.sh diff --git a/merge-array-by-key.sh b/merge-array-by-key.sh new file mode 100755 index 00000000..09481e62 --- /dev/null +++ b/merge-array-by-key.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# ./yq ea '.[]' examples/data*.yaml + + +./yq ea ' + ((.[] | {.name: .}) as $item ireduce ({}; . * $item )) as $uniqueMap + | ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value) +' examples/data*.yaml \ No newline at end of file diff --git a/pkg/yqlib/doc/multiply-merge.md b/pkg/yqlib/doc/multiply-merge.md index 000c8536..5e576b13 100644 --- a/pkg/yqlib/doc/multiply-merge.md +++ b/pkg/yqlib/doc/multiply-merge.md @@ -239,6 +239,8 @@ so that there are no duplicates. The second half converts that map back to an ar To use this, you will need to update '.[]' to be the expression to your array (e.g. .my.array[]), and '.a' to be the key field of your array (e.g. '.name') +Thanks Kev from [stackoverflow](https://stackoverflow.com/a/70109529/1168223) + Given a sample.yml file of: ```yaml diff --git a/pkg/yqlib/operator_multiply_test.go b/pkg/yqlib/operator_multiply_test.go index d95a6152..cff562e8 100644 --- a/pkg/yqlib/operator_multiply_test.go +++ b/pkg/yqlib/operator_multiply_test.go @@ -33,6 +33,8 @@ var mergeArraysObjectKeysText = `There are two parts of the complex expression. so that there are no duplicates. The second half converts that map back to an array. To use this, you will need to update '.[]' to be the expression to your array (e.g. .my.array[]), and '.a' to be the key field of your array (e.g. '.name') + +Thanks Kev from [stackoverflow](https://stackoverflow.com/a/70109529/1168223) ` var mergeExpression = `((.[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap From f5f148cadb73b2565c01655b6112c8650dbaf167 Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Mon, 29 Nov 2021 21:06:09 +1100 Subject: [PATCH 10/11] Better formatting of merge arrays example --- pkg/yqlib/doc/multiply-merge.md | 5 +++-- pkg/yqlib/operator_multiply_test.go | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/yqlib/doc/multiply-merge.md b/pkg/yqlib/doc/multiply-merge.md index 5e576b13..581c18dc 100644 --- a/pkg/yqlib/doc/multiply-merge.md +++ b/pkg/yqlib/doc/multiply-merge.md @@ -262,8 +262,9 @@ And another sample another.yml file of: ``` then ```bash -yq eval-all '((.[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap -| ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value) +yq eval-all ' + ((.[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap + | ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value) ' sample.yml another.yml ``` will output diff --git a/pkg/yqlib/operator_multiply_test.go b/pkg/yqlib/operator_multiply_test.go index cff562e8..dc377008 100644 --- a/pkg/yqlib/operator_multiply_test.go +++ b/pkg/yqlib/operator_multiply_test.go @@ -37,8 +37,9 @@ To use this, you will need to update '.[]' to be the expression to your array (e Thanks Kev from [stackoverflow](https://stackoverflow.com/a/70109529/1168223) ` -var mergeExpression = `((.[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap -| ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value) +var mergeExpression = ` + ((.[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap + | ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value) ` var docWithHeader = `# here From 176fec639dda540c6650437153eb9d138bbf8d95 Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Mon, 29 Nov 2021 21:28:25 +1100 Subject: [PATCH 11/11] Better merge example --- pkg/yqlib/doc/multiply-merge.md | 60 +++++++++++++++++------------ pkg/yqlib/operator_multiply_test.go | 19 +++++---- 2 files changed, 47 insertions(+), 32 deletions(-) diff --git a/pkg/yqlib/doc/multiply-merge.md b/pkg/yqlib/doc/multiply-merge.md index 581c18dc..7f83a495 100644 --- a/pkg/yqlib/doc/multiply-merge.md +++ b/pkg/yqlib/doc/multiply-merge.md @@ -234,50 +234,60 @@ will output ``` ## Merge arrays of objects together, matching on a key -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', -so that there are no duplicates. The second half converts that map back to an array. +There are several parts of the complex expression. +The first part is doing the hard work, it creates a map from the arrays keyed by '.a', so that there are no duplicates. +Then there's another reduce that converts that map back to an array. +Finally, we set the result of the merged array back into the first doc. -To use this, you will need to update '.[]' to be the expression to your array (e.g. .my.array[]), and '.a' to be the key field of your array (e.g. '.name') +To use this, you will need to update '.myArray' to be the expression to your array (e.g. .my.array), and '.a' to be the key field of your array (e.g. '.name') Thanks Kev from [stackoverflow](https://stackoverflow.com/a/70109529/1168223) Given a sample.yml file of: ```yaml -- a: apple - b: appleB -- a: kiwi - b: kiwiB -- a: banana - b: bananaB +myArray: + - a: apple + b: appleB + - a: kiwi + b: kiwiB + - a: banana + b: bananaB +something: else ``` And another sample another.yml file of: ```yaml -- a: banana - c: bananaC -- a: apple - b: appleB2 -- a: dingo - c: dingoC +myArray: + - a: banana + c: bananaC + - a: apple + b: appleB2 + - a: dingo + c: dingoC ``` then ```bash yq eval-all ' - ((.[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap +( + ((.myArray[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap | ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value) +) as $mergedArray +| select(fi == 0) | .myArray = $mergedArray ' sample.yml another.yml ``` will output ```yaml -- a: apple - b: appleB2 -- a: kiwi - b: kiwiB -- a: banana - b: bananaB - c: bananaC -- a: dingo - c: dingoC +myArray: + - a: apple + b: appleB2 + - a: kiwi + b: kiwiB + - a: banana + b: bananaB + c: bananaC + - a: dingo + c: dingoC +something: else ``` ## Merge to prefix an element diff --git a/pkg/yqlib/operator_multiply_test.go b/pkg/yqlib/operator_multiply_test.go index dc377008..0ad67299 100644 --- a/pkg/yqlib/operator_multiply_test.go +++ b/pkg/yqlib/operator_multiply_test.go @@ -29,17 +29,22 @@ var mergeArrayWithAnchors = `sample: - <<: *a ` -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', -so that there are no duplicates. The second half converts that map back to an array. +var mergeArraysObjectKeysText = `There are several parts of the complex expression. +The first part is doing the hard work, it creates a map from the arrays keyed by '.a', so that there are no duplicates. +Then there's another reduce that converts that map back to an array. +Finally, we set the result of the merged array back into the first doc. -To use this, you will need to update '.[]' to be the expression to your array (e.g. .my.array[]), and '.a' to be the key field of your array (e.g. '.name') +To use this, you will need to update '.myArray' to be the expression to your array (e.g. .my.array), and '.a' to be the key field of your array (e.g. '.name') Thanks Kev from [stackoverflow](https://stackoverflow.com/a/70109529/1168223) ` var mergeExpression = ` - ((.[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap +( + ((.myArray[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap | ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value) +) as $mergedArray +| select(fi == 0) | .myArray = $mergedArray ` var docWithHeader = `# here @@ -378,11 +383,11 @@ var multiplyOperatorScenarios = []expressionScenario{ { description: "Merge arrays of objects together, matching on a key", subdescription: mergeArraysObjectKeysText, - 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}]`, + document: `{myArray: [{a: apple, b: appleB}, {a: kiwi, b: kiwiB}, {a: banana, b: bananaB}], something: else}`, + document2: `myArray: [{a: banana, c: bananaC}, {a: apple, b: appleB2}, {a: dingo, c: dingoC}]`, expression: mergeExpression, expected: []string{ - "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", + "D0, P[], (doc)::{myArray: [{a: apple, b: appleB2}, {a: kiwi, b: kiwiB}, {a: banana, b: bananaB, c: bananaC}, {a: dingo, c: dingoC}], something: else}\n", }, }, {