简体   繁体   中英

How do I avoid creating a cross product when extracting multiple sub-elements from a list in JQ?

I'm getting product information from a vendor. It's got a bajillion fields in it, but I have this trimmed down to just relevant fields. I'm anticipating the solution has something to do with map() , but I just haven't been able to wrap my head around it.

When I try and get multiple fields out of a sub-dictionary, it does a cross product. I'm expecting 2 lines back in this example, but I get 4.

Fiddle
Expected output:

{
  "sku": "1234",
  "desc": "Pink Ring",
  "img_url": "https://provider.com/rings/1234_A",
  "img_angle": "ViewA"
}
{
  "sku": "1234",
  "desc": "Pink Ring",
  "img_url": "https://provider.com/rings/1234_B",
  "img_angle": "ViewB"
}

Starting data:

{
  "Products": [
    {
      "SKU": "1234",
      "Description": "Pink Ring",
      "RingSize": 7,
      "Images": [
        {
          "FullUrl": "https://provider.com/rings/1234_A",
          "SortOrder": 1,
          "Angle": "ViewA"
        },
        {
          "FullUrl": "https://provider.com/rings/1234_B",
          "SortOrder": 2,
          "Angle": "ViewB"
        }
      ]
    }
  ]
}

I then pass it through this filter:

.Products[] | { sku: .SKU, desc: .Description, img_url: .Images[].FullUrl, img_angle: .Images[].Angle }

This gives me the following data:

{
  "sku": "1234",
  "desc": "Pink Ring",
  "img_url": "https://provider.com/rings/1234_A",
  "img_angle": "ViewA"
}
{
  "sku": "1234",
  "desc": "Pink Ring",
  "img_url": "https://provider.com/rings/1234_A",
  "img_angle": "ViewB"
}
{
  "sku": "1234",
  "desc": "Pink Ring",
  "img_url": "https://provider.com/rings/1234_B",
  "img_angle": "ViewA"
}
{
  "sku": "1234",
  "desc": "Pink Ring",
  "img_url": "https://provider.com/rings/1234_B",
  "img_angle": "ViewB"
}

This is what I'm hoping for. You can see URL_A and ANGLE_A don't cross multiply with URL_B and ANGLE_B.

{
  "sku": "1234",
  "desc": "Pink Ring",
  "img_url": "https://provider.com/rings/1234_A",
  "img_angle": "ViewA"
}
{
  "sku": "1234",
  "desc": "Pink Ring",
  "img_url": "https://provider.com/rings/1234_B",
  "img_angle": "ViewB"
}

Please don't assume that you can trust img_url and img_angle to have values that reference each other - you definitely can't, that's only here for illustration purposes.

I've tried several things that keep giving me a cross product and don't actually change the output, like { sku: .SKU, desc: .Description } + { img_url: .Images[].FullUrl } + { img_angle: .Images[].Angle } .

I've also tried adapting recipes from this recipe book and this cheat sheet . I haven't been able to get anything useful that doesn't puke at runtime.

You can see STREAM as $var as creating a foreach loop.

.Products[] |
.Images[] as $img |
{ sku: .SKU, desc: .Description, img_url: $img.FullUrl, img_angle: $img.Angle }

jqplay


We can show this is equivalent to other answer.

Let's start by factoring out $img .

.Products[] |
.Images[] as $img |
{ sku: .SKU, desc: .Description } +
( $img | { img_url: .FullUrl, img_angle: .Angle } )

Now we can inline the variable because 1) it's only used once and 2) the topic ( . ) is the same.

.Products[] |
{ sku: .SKU, desc: .Description } +
( .Images[] | { img_url: .FullUrl, img_angle: .Angle } )

And we're already there.

Is this what you are looking for:

.Products[] | {sku: .SKU, desc: .Description} + (
  .Images[] | {img_url: .FullUrl, img_angle: .Angle}
)

Fiddle

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM