Mapping from file in jq - Stack Overflow

I'm trying to use jq to look up data from a json file with account mappings. So given an account n

I'm trying to use jq to look up data from a json file with account mappings. So given an account number as input, I want to look up it's name from a file, and it needs to handle the account not being found.

echo '["1100", "1350"]' | jq --slurpfile accountsdata accounts.json '
    def get_account_data(account):
        [$accountsdata[]
        | .[]
        | select((.accountnumber | tostring) == (account | tostring))] as $output
        | if $output | length == 0 then {"name": ("no mapping for " + account + ".")} else $output[0] end;

    def get_name(account):
        get_account_data(account).name;

. | map(get_name(.))
'

The account mapping file is as follows:

[
  {
    "accountnumber": 1100,
    "name": "Account A"
  },
  {
    "accountnumber": 1350,
    "name": "Account B"
  },
  {
    "accountnumber": 1356,
    "name": "Account C"
  }
]

Expected output:

[
  "Account A",
  "Account B"
]

Actual output:

[
  "no mapping for 1100.",
  "no mapping for 1350."
]

However, if I change the call from . | map(get_name(.)) to . | map(get_name("1100")) (i.e. hardcode the accountnumber), I get the expected

[
  "Account A",
  "Account A"
]

What am I missing?

I'm trying to use jq to look up data from a json file with account mappings. So given an account number as input, I want to look up it's name from a file, and it needs to handle the account not being found.

echo '["1100", "1350"]' | jq --slurpfile accountsdata accounts.json '
    def get_account_data(account):
        [$accountsdata[]
        | .[]
        | select((.accountnumber | tostring) == (account | tostring))] as $output
        | if $output | length == 0 then {"name": ("no mapping for " + account + ".")} else $output[0] end;

    def get_name(account):
        get_account_data(account).name;

. | map(get_name(.))
'

The account mapping file is as follows:

[
  {
    "accountnumber": 1100,
    "name": "Account A"
  },
  {
    "accountnumber": 1350,
    "name": "Account B"
  },
  {
    "accountnumber": 1356,
    "name": "Account C"
  }
]

Expected output:

[
  "Account A",
  "Account B"
]

Actual output:

[
  "no mapping for 1100.",
  "no mapping for 1350."
]

However, if I change the call from . | map(get_name(.)) to . | map(get_name("1100")) (i.e. hardcode the accountnumber), I get the expected

[
  "Account A",
  "Account A"
]

What am I missing?

Share asked Mar 4 at 11:49 sjoblomjsjoblomj 1342 silver badges10 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

What am I missing?

The function get_account_data(account) defines account as a function, so it won't be evaluated immediately. Thus, when calling get_account_data with . as the argument, any reference of account inside of it will be substituted by the function ., and then evaluated in that target context. So, (.accountnumber | tostring) == (account | tostring) would become (.accountnumber | tostring) == (. | tostring), with . being evaluated to the current context, which by then is different to the items from the input (which has been the context at the time of calling the function). To mitigate this, call the function by value by defining its argument as a variable, i.e. get_account_data($account). This way, it is the value being passed over, so (.accountnumber | tostring) == ($account | tostring) becomes (.accountnumber | tostring) == ("1100" | tostring) in the first iteration, etc.

Here's a simplified version of your approach:

echo '["1100", "1234", "1350"]' | jq --slurpfile accountsdata accounts.json '

  def get_account_data($account):
    [ $accountsdata[][]
      | select(.accountnumber | tostring == $account)
    ] as $output
    | if $output | length == 0 then {name: "no mapping for \($account)."}
      else $output[0] end;

  def get_name:
    get_account_data(.).name;

  map(get_name)
'
[
  "Account A",
  "no mapping for 1234.",
  "Account B"
]

However, I'd rather create a lookup object which you can query repeatedly without iterating over the accounts data again and again for each input number. For creating such object, you could employ the INDEX function, and combine it with JOIN to produce the matches, while defaulting with // to another expression if there's no match, as accessing a missing object key (i.e. performing an unsuccessful lookup) always evaluates to null:

echo '["1100", "1234", "1350"]' | jq --slurpfile accountsdata accounts.json '[
  JOIN(INDEX($accountsdata[][]; .accountnumber);
    .[]; .; last.name // "no mapping for \(first)."
  )
]'
[
  "Account A",
  "no mapping for 1234.",
  "Account B"
]

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745045329a4608063.html

相关推荐

  • Mapping from file in jq - Stack Overflow

    I'm trying to use jq to look up data from a json file with account mappings. So given an account n

    21小时前
    10

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信