Home > other >  JQ Add key/value to json object in order to enumerate the objects
JQ Add key/value to json object in order to enumerate the objects

Time:11-25

I have a list of objects (20 in total) and I need to insert a new key-value pair with the positional number of each object (values in range 1 to 20). I have managed to put together this code, however I end up replicating the objects inside of the array so instead of 20 objects I end up with about 100.

jq "(.data.items, .data.primaryItemResultList.items)| values | length as $l | values[]  = {ranking: range(1, $l)}| .[]"

When I ty to add a static value to the "ranking" it works correctly, however if I use the range function it doesn't produce the desired output as mentioned before.

Here is an example of the shortened code:

{
  "data": {
    "items": [
      {
        "id": "items_10244-20964274",
        "size": "80 ct",
        "productId": "20964274",
        "brandName": "peets",
        "brandId": "25555",
        "retailer": {
          "isUltrafast": false,
          "__typename": "RetailersRetailer"
        },
      },
      {
        "id": "items_10244-17284948",
        "size": "75 ct",
        "productId": "17284948",
        "legacyId": "2991007854",
        "brandName": "peet's",
        "brandId": "50954",
        "retailer": {
          "isUltrafast": false,
          "__typename": "RetailersRetailer"
        },
      },
      {
        "id": "items_10244-19232655",
        "size": "3 lb",
        "productId": "19232655",
        "brandName": "kirkland signature",
        "brandId": "7632",
        "retailer": {
          "isUltrafast": false,
          "__typename": "RetailersRetailer"
      }
    ]
  }
}

Would anyone be able to help with this issue and identify the mistake?

The expected output is:

{
  "data": {
    "items": [
      {
        "id": "items_10244-20964274",
        "size": "80 ct",
        "productId": "20964274",
        "brandName": "peets",
        "brandId": "25555",
        "ranking": 1,
        "retailer": {
          "isUltrafast": false,
          "__typename": "RetailersRetailer"
        },
      },
      {
        "id": "items_10244-17284948",
        "size": "75 ct",
        "productId": "17284948",
        "legacyId": "2991007854",
        "brandName": "peet's",
        "brandId": "50954",
        "ranking": 2,
        "retailer": {
          "isUltrafast": false,
          "__typename": "RetailersRetailer"
        },
      },
      {
        "id": "items_10244-19232655",
        "size": "3 lb",
        "productId": "19232655",
        "brandName": "kirkland signature",
        "brandId": "7632",
        "ranking": 3,
        "retailer": {
          "isUltrafast": false,
          "__typename": "RetailersRetailer"
      }
    ]
  }

CodePudding user response:

You could exploit the circumstance that to_entries, when applied to an array, will use the (0-based) item index as .key. Add 1 to make it 1-based.

.data.items |= [to_entries[] | .value   {ranking: (.key 1)}]

Demo

For an approach based on range(length), I'd use transpose to zip the items array with the indices array:

.data.items |= ([., [range(length) 1]] | transpose | map(.[0]   {ranking: .[1]}))

Demo

Output:

{
  "data": {
    "items": [
      {
        "id": "items_10244-20964274",
        "size": "80 ct",
        "productId": "20964274",
        "brandName": "peets",
        "brandId": "25555",
        "retailer": {
          "isUltrafast": false,
          "__typename": "RetailersRetailer"
        },
        "ranking": 1
      },
      {
        "id": "items_10244-17284948",
        "size": "75 ct",
        "productId": "17284948",
        "legacyId": "2991007854",
        "brandName": "peet's",
        "brandId": "50954",
        "retailer": {
          "isUltrafast": false,
          "__typename": "RetailersRetailer"
        },
        "ranking": 2
      },
      {
        "id": "items_10244-19232655",
        "size": "3 lb",
        "productId": "19232655",
        "brandName": "kirkland signature",
        "brandId": "7632",
        "retailer": {
          "isUltrafast": false,
          "__typename": "RetailersRetailer"
        },
        "ranking": 3
      }
    ]
  }
}

Note: JSON does not support or recognize the ordering of object fields. Thus, the actual position of the new ranking field makes no structural difference. You can, however, tweak jq into changing the textual representation it generates for output. For instance, to move the retailer field to last position, remove it and add it again with del(.retailer) {retailer} (See demos for the to_entries and the range/transpose approaches). But keep in mind that this modification is only aesthetical. Any JSON post-processor may disregard this ordering again.

CodePudding user response:

You're looking for something like this:

.data.items |= [range(length) as $i | .[$i]   {ranking: ($i   1)}]

Online demo

  • Related