# Quick conversion of multiple values using with_entries in jq

This blog post demonstrates how powerful the combination of jq's `to_entries`

and `from_entries`

can be, and show how `with_entries`

is a great extension of that.

I pulled some stats from the YouTube Data API v3 for the episodes so far in our Back to basics: CAP Node.js Hands-on SAP Dev live stream series. Surprisingly, the values for numbers of views and likes and so on are in string representation. Here's what the dataset (in a file called `series.json`

) looks like as of right now:

`[`

{

"id": "gu5r1EWSDSU",

"title": "Back to basics with CAP - part 1",

"statistics": {

"viewCount": "8916",

"likeCount": "247",

"favoriteCount": "0",

"commentCount": "15"

}

},

{

"id": "8N2TxgZ9bjY",

"title": "Back to basics with CAP - part 2",

"statistics": {

"viewCount": "4045",

"likeCount": "91",

"favoriteCount": "0",

"commentCount": "5"

}

},

{

"id": "mTvjAthGjBg",

"title": "Back to basics with CAP - part 3",

"statistics": {

"viewCount": "2708",

"likeCount": "79",

"favoriteCount": "0",

"commentCount": "11"

}

},

{

"id": "1ywiOaGVA5w",

"title": "Back to basics with CAP - part 4",

"statistics": {

"viewCount": "2082",

"likeCount": "72",

"favoriteCount": "0",

"commentCount": "8"

}

},

{

"id": "fgqnptEgUW4",

"title": "Back to basics with CAP - part 5",

"statistics": {

"viewCount": "1926",

"likeCount": "47",

"favoriteCount": "0",

"commentCount": "8"

}

},

{

"id": "NZj7Q4LBotA",

"title": "Back to basics with CAP - part 6",

"statistics": {

"viewCount": "1545",

"likeCount": "43",

"favoriteCount": "0",

"commentCount": "11"

}

}

]

If you look at the videos resource documentation, you'll see that the intended representations for these resources are indeed strings:

Anyway, for various reasons, including a desire to surface this info in a custom Home Assistant dashboard, and to be able to perform calculations upon the values, I wanted all the figures as numbers rather than strings.

## Another job for with_entries

While using `with_entries`

is not entirely natural for me yet, I find I'm only a step away, because I know that `to_entries`

brings me from what I am starting with to something a lot closer to a structure that I can automatically manipulate. What I mean is that identifying the four separate properties within the `statistics`

object is difficult to do automatically as they have dynamic names, but using `to_entries`

makes that problem go away, especially with its sibling `from_entries`

to turn things back again to how they were.

And once I have got that straight in my head, I know I can turn to the cousin of `to_entries`

and `from_entries`

, namely `with_entries`

.

### Using to_entries

Here's an example of what `to_entries`

does to the `statistics`

object in the first object in the array (to keep things brief).

In all the following examples, I'll just show the jq. For example, the

`first | .statistics`

jq directly below would actually be invoked like this:`jq 'first | .statistics' series.json`

. Also, longer jq invocations will be wrapped with newlines for readability.

First, let's identify the focus of transformation:

`first | .statistics`

This shows us:

`{`

"viewCount": "8916",

"likeCount": "247",

"favoriteCount": "0",

"commentCount": "15"

}

Then, applying `to_entries`

like this:

`first | .statistics | to_entries`

we get:

`[`

{

"key": "viewCount",

"value": "8916"

},

{

"key": "likeCount",

"value": "247"

},

{

"key": "favoriteCount",

"value": "0"

},

{

"key": "commentCount",

"value": "15"

}

]

Now each of the properties (e.g. `"viewCount": "8916"`

) are normalised into objects, each containing static key names `key`

and `value`

(e.g. `{ "key": "viewCount", "value": "8916" }`

), and all these objects are contained in an array.

This then means we can apply a general transformation over that array. So let's try `tonumber`

, like this:

`first | .statistics | to_entries `

| map(.value |= tonumber)

This results in:

`[`

{

"key": "viewCount",

"value": 8916

},

{

"key": "likeCount",

"value": 247

},

{

"key": "favoriteCount",

"value": 0

},

{

"key": "commentCount",

"value": 15

}

]

### Using from_entries

And to get back to the structure we started with is a job for `from_entries`

:

`first | .statistics | to_entries`

| map(.value |= tonumber)

| from_entries

This results in:

`{`

"viewCount": 8916,

"likeCount": 247,

"favoriteCount": 0,

"commentCount": 15

}

Nice!

### Using with_entries

Using `to_entries`

, mapping over the entries in the resulting array, then using `from_entries`

is such a common pattern that there's also `with_entries`

which is a built-in defined itself in jq:

`def with_entries(f): to_entries | map(f) | from_entries;`

So we can reduce the previous incantation down to:

`first | .statistics | with_entries(.value |= tonumber)`

This gives us exactly the same result.

## Putting it all together

So using `with_entries`

we can transform the statistics properties of all of the video entries, like this:

`map(.statistics |= with_entries(.value |= tonumber))`

`[`

{

"id": "gu5r1EWSDSU",

"title": "Back to basics with CAP - part 1",

"statistics": {

"viewCount": 8916,

"likeCount": 247,

"favoriteCount": 0,

"commentCount": 15

}

},

{

"id": "8N2TxgZ9bjY",

"title": "Back to basics with CAP - part 2",

"statistics": {

"viewCount": 4045,

"likeCount": 91,

"favoriteCount": 0,

"commentCount": 5

}

},

{

"id": "mTvjAthGjBg",

"title": "Back to basics with CAP - part 3",

"statistics": {

"viewCount": 2708,

"likeCount": 79,

"favoriteCount": 0,

"commentCount": 11

}

},

{

"id": "1ywiOaGVA5w",

"title": "Back to basics with CAP - part 4",

"statistics": {

"viewCount": 2082,

"likeCount": 72,

"favoriteCount": 0,

"commentCount": 8

}

},

{

"id": "fgqnptEgUW4",

"title": "Back to basics with CAP - part 5",

"statistics": {

"viewCount": 1926,

"likeCount": 47,

"favoriteCount": 0,

"commentCount": 8

}

},

{

"id": "NZj7Q4LBotA",

"title": "Back to basics with CAP - part 6",

"statistics": {

"viewCount": 1545,

"likeCount": 43,

"favoriteCount": 0,

"commentCount": 11

}

}

]

Perfect!