Home > Blockchain >  Select random id from list in jq and update value
Select random id from list in jq and update value

Time:03-07

I have some sample payload that I am going to be receiving, it looks like this:

[
  {
    "Id": "9",
    "Line": [
      {
        "Amount": 100,
        "Description": "Weekly Gardening Service",
        "DetailType": "SalesItemLineDetail",
        "Id": "1",
        "LineNum": 1,
        "SalesItemLineDetail": {
          "ItemAccountRef": {
            "name": "Landscaping Services",
            "value": "45"
          },
          "ItemRef": {
            "name": "Gardening",
            "value": "6"
          },
          "Qty": 4,
          "TaxCodeRef": {
            "value": "TAX"
          },
          "UnitPrice": 25
        }
      },
      {
        "Amount": 100,
        "DetailType": "SubTotalLineDetail",
        "SubTotalLineDetail": {}
      }
    ]
  },
  {
    "Id": "10",
    "Line": [
      {
        "Amount": 140,
        "Description": "Weekly Gardening Service",
        "DetailType": "SalesItemLineDetail",
        "Id": "1",
        "LineNum": 1,
        "SalesItemLineDetail": {
          "ItemAccountRef": {
            "name": "Landscaping Services",
            "value": "45"
          },
          "ItemRef": {
            "name": "Gardening",
            "value": "6"
          },
          "Qty": 4,
          "TaxCodeRef": {
            "value": "NON"
          },
          "UnitPrice": 35
        }
      },
      {
        "Amount": 35,
        "Description": "Pest Control Services",
        "DetailType": "SalesItemLineDetail",
        "Id": "2",
        "LineNum": 2,
        "SalesItemLineDetail": {
          "ItemAccountRef": {
            "name": "Pest Control Services",
            "value": "54"
          },
          "ItemRef": {
            "name": "Pest Control",
            "value": "10"
          },
          "Qty": 1,
          "TaxCodeRef": {
            "value": "NON"
          },
          "UnitPrice": 35
        }
      },
      {
        "Amount": 175,
        "DetailType": "SubTotalLineDetail",
        "SubTotalLineDetail": {}
      }
    ]
  }
]

These I know are valid and I need to cross reference them, by id, in another payload I am receiving. But, the data I am receiving I can't assume to have valid ID's.

So, I want to take all the valid Ids from above, and shove them, randomly, into the sample data I have, that looks like this ($.invoices[].qbId):

[
  {
    "id": "fb2430c5-5970-46b0-9947-aaa0b9f177bb",
    "invoices": [
      {
        "description": "2022-02-03 - 179",
        "dueDate": "2022-02-03T22:51:10.206Z",
        "id": "6f904b18-71c6-4fec-a016-7452f6a6b1dc",
        "invoiceDate": "2022-02-03T22:51:10.347Z",
        "openBalance": 200,
        "paidAmount": 200,
        "qbId": "1",
        "totalAmount": 212
      }
    ]
  },
  {
    "id": "fa5b77b5-bfd4-4178-ac31-386ec83f530c",
    "invoices": [
      {
        "description": "2022-01-12 - 95",
        "dueDate": "2022-01-12T14:08:26.219Z",
        "id": "05a58be3-4396-4c15-b9c2-ece68cb2b3fb",
        "invoiceDate": "2022-01-12T14:08:26.399Z",
        "openBalance": 7.33,
        "paidAmount": 7.33,
        "qbId": "",
        "totalAmount": 7.33
      },
      {
        "description": "2022-01-12 - 95",
        "dueDate": "2022-01-12T14:08:26.219Z",
        "id": "91f5ecd0-e18d-4029-8745-143323e02007",
        "invoiceDate": "2022-01-12T14:08:26.580Z",
        "openBalance": 53.13,
        "paidAmount": 53.13,
        "qbId": "",
        "totalAmount": 53.13
      }
    ]
  }
]

this jq will get me my ids jq '.QueryResponse.Invoice | map(.Id)' which can be readily consumed by jq. The question now is (and this is what I don't know) how to randomly choose from this array and update the sample payload:

jq 'map(.   {
   invoices : .invoices | map(.   {qbId: ??random here })
   })
'

CodePudding user response:

If I understood correctly, you want to replace each id field (spelling may differ, sometimes it's Id) with a randomly generated id string.

This solution first extracts the paths of all such id fields (in various spellings) using jq, then iterates over the result in the shell, using uuidgen to generate an id for each, which is fed into another jq call which uses setpath to change the value at the paths saved to the ids generated:

file="input.json"

jq -c '
  paths(.. | scalars) | select(.[-1] == ("id", "Id", "ID")) | tojson
' "$file" |
while read -r json; do printf '["%s",%s]\n' "$(uuidgen)" "$json"; done |
jq -n --argfile file "$file" '
  reduce inputs as [$id,$json] ($file; setpath($json | fromjson; $id))
'
[
  {
    "Id": "10162eb7-29ba-4b60-ad20-e5b1133eca63",
    "Line": [
      {
        "Amount": 100,
        "Description": "Weekly Gardening Service",
        "DetailType": "SalesItemLineDetail",
        "Id": "272832df-a8f5-4877-92de-1545150afc33",
        "LineNum": 1,
        "SalesItemLineDetail": {
          "ItemAccountRef": {
            "name": "Landscaping Services",
            "value": "45"
          },
          "ItemRef": {
            "name": "Gardening",
            "value": "6"
          },
          "Qty": 4,
          "TaxCodeRef": {
            "value": "TAX"
          },
          "UnitPrice": 25
        }
      },
      {
        "Amount": 100,
        "DetailType": "SubTotalLineDetail",
        "SubTotalLineDetail": {}
      }
    ]
  },
  {
    "Id": "190b0e50-e007-46a4-b1ca-c3efb762629c",
    "Line": [
      {
        "Amount": 140,
        "Description": "Weekly Gardening Service",
        "DetailType": "SalesItemLineDetail",
        "Id": "f7067227-56d4-4849-873a-3ee5c336999e",
        "LineNum": 1,
        "SalesItemLineDetail": {
          "ItemAccountRef": {
            "name": "Landscaping Services",
            "value": "45"
          },
          "ItemRef": {
            "name": "Gardening",
            "value": "6"
          },
          "Qty": 4,
          "TaxCodeRef": {
            "value": "NON"
          },
          "UnitPrice": 35
        }
      },
      {
        "Amount": 35,
        "Description": "Pest Control Services",
        "DetailType": "SalesItemLineDetail",
        "Id": "181d7c6b-0afa-4f44-a568-2c482fc5c285",
        "LineNum": 2,
        "SalesItemLineDetail": {
          "ItemAccountRef": {
            "name": "Pest Control Services",
            "value": "54"
          },
          "ItemRef": {
            "name": "Pest Control",
            "value": "10"
          },
          "Qty": 1,
          "TaxCodeRef": {
            "value": "NON"
          },
          "UnitPrice": 35
        }
      },
      {
        "Amount": 175,
        "DetailType": "SubTotalLineDetail",
        "SubTotalLineDetail": {}
      }
    ]
  }
]

CodePudding user response:

This shows how to select elements at random from an array, assuming a bash or sufficiently bash-like environment:

#!/bin/bash

< /dev/urandom tr -cd '0-9' | fold -w 1 | jq -MRnc '

# Output: a prn in range(0;$n) where $n is `.`
def prn:
  if . == 1 then 0
  else . as $n
  | ([1, (($n-1)|tostring|length)]|max) as $w
  | [limit($w; inputs)] | join("") | tonumber
  | if . < $n then . else ($n | prn) end
  end;

# Input: an array
# Output: an array, being a selection of $k elements from . chosen at random without replacement
def prns($k):
  if $k <= 0 then []
  else . as $in
  | length as $n
  | if $k > $n then "no can do" | error
    else ($n|prn) as $ix
    | [$in[$ix]]   (($in[0:$ix]   $in[$ix 1:])|prns($k-1))
    end
  end;


# Two illustrations
# Three from range(0,10) (with replacement):
[range(0;10) | ( ["a", "b", "c"] | .[length|prn]) ],

# Three from an array, without replacement:
([range(0;10)] | prns(3))

'
  • Related