Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to conditionally select value with JQ

I am trying to select 1 price if it exists, otherwise I want to select a "default" price which always exists. My JQ works if the RMP price doesn’t exist, I just get the 1 value back. But as you can see, if RMP exists I end up with 2 entries … one with each price. I am only looking for 1 result back. It will either have the RMP price if it exists, or it will have the RET price. Not sure what I’m doing wrong here.

JSON

[
  {
    "PartNumber": "ABC123",
    "Prices": {
      "Pricing": [
        {
          "@PriceType": "RET",
          "Price": {
            "#text": "230.3800"
          }
        },
        {
          "@PriceType": "LST",
          "Price": {
            "#text": "230.3800"
          }
        },
        {
          "@PriceType": "RMP",
          "Price": {
            "#text": "152.0000"
          }
        }
      ]
    }
  }
]

JQ

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

[.[] | {
    sku: .PartNumber,
    price: (.Prices?.Pricing? | if type == "array" then .[] else . end | if any(.; ."@PriceType" == "RMP") then select(."@PriceType"? == "RMP").Price."#text" else select(."@PriceType"? == "RET").Price."#text" end),
}]

RESULT

[
  {
    "sku": "ABC123",
    "price": "230.3800"
  },
  {
    "sku": "ABC123",
    "price": "152.0000"
  }
]

>Solution :

The "problem" of your approach is with if type == "array" then .[] else . end. As .Prices.Pricing is indeed an array, this branches to .[], destructuring the array, so the following code is executed three times, once for each item. The first one will produce the default item (as there is nothing else), the second outputs nothing (neither the target nor the default is present), and the third immediately finds the target item.

My approach would be using INDEX to turn the array into an object, and the alternative operator // to select a default if the previous returns null:

map({
  sku: .PartNumber,
  price: (.Prices.Pricing | INDEX(."@PriceType") | .RMP // .RET | .Price."#text")
})
[
  {
    "sku": "ABC123",
    "price": "152.0000"
  }
]

Demo

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading