What's JQ?

What's JQ?

JQ ဆိုတာ JSON data တွေကို command line မှာ process လုပ်ဖို့အသုံးပြုတဲ့ command-line JSON processor တစ်ခုဖြစ်ပါတယ်။ JSON data ကို query, filter, transform, နှင့် manipulate လုပ်ဖို့အတွက် အထူးသင့်တော်ပါတယ်။ JQ ဟာ lightweight ဖြစ်ပြီး Linux, macOS, Windows အပါအဝင် OS အများစုမှာ run လုပ်နိုင်ပါတယ်။

Functions of JQ

JQ command line tool ဖြင့် အောက်ပါ functions တွေကို စွမ်းဆောင်နိုင်သည်။

  1. JSON Parsing: JSON data ကို parse လုပ်ပြီး tree structure အနေနဲ့ ကိုင်တွယ်နိုင်စေတယ်။

  2. Filtering: JSON data ထဲက လိုအပ်တဲ့ fields, objects, အဖြစ် filter လုပ်နိုင်တယ်။

  3. Transformation: JSON data ကို one form to another form သို့ ပြောင်းပေးနိုင်တယ်။

  4. Formatting: JSON data ကို human-readable ဖြစ်အောင် format ပြုလုပ်ခြင်းနှင့် pretty-print ဖြစ်အောင် display ပြသပေးနိုင်တယ်။

  5. Composing: Multiple filters တွေကို combine လုပ်ပြီး complex queries တွေရေးနိုင်တယ်။

Challenges in Handling JSON from the Command Line

JSON ကို modern API တွေနှင့် data services အများစုတွင် အသုံးပြုလေ့ရှိသော popular ဖြစ်သည့် structured data format တစ်မျိုးဖြစ်သည်။ ၎င်းသည် lightweight design ဖြစ်သည့် အပြင် JavaScript နှင့် တွဲဖက်အသုံးပြုနိုင်သောကြောင့် online applications တွေမှာ အများဆုံးတွေ့ရသည်။

Bash ကဲ့သို့သော shell များတွင် JSON ကို natively understand and manipulate မပြုလုပ်နိုင်ပါ။ ဒါကြောင့် command line မှတဆင့် JSON ကို ကိုင်တွယ်ရသည်မှာ အချိန်စားနိုင်ပါသည်။

For example: sed နှင့် grep ကဲ့သို့သော text manipulation tool များကို အသုံးပြုရခြင်းကြောင့် ဖြစ်သည်။

How to Install jq

1. Linux

  • Debian/Ubuntu: sudo apt install jq

  • Fedora: sudo dnf install jq

  • Arch: sudo pacman -S jq

  • Manual: Download binary, make it executable, and move to /usr/local/bin.

2. macOS

  • Use Homebrew:

      brew install jq
    

3. Windows

  • Chocolatey:

      choco install jq
    
  • Manual: Download from GitHub and add to PATH.

4. Docker

  • Run jq inside a container:

      docker run --rm -i stedolan/jq jq
    

5. Verify Installation

If the installation was successful, the console will display the version, usage examples, and other information.

Working With Simple Filters

jq သည် JSON data တွင် filter များကို အသုံးပြုသည့် နည်းလမ်းဖြင့် အလုပ်လုပ်သည်။ Filter တစ်ခုစီသည် input ကို လက်ခံပြီး JSON ကို output အဖြစ် ပြန်ပေးသည်။ Preconfigured filter များစွာရှိပြီး၊ pipeline များဖြင့် ပေါင်းစပ်ကာ JSON data တွင် ရိုးရှင်းသည့်အပြင် အဆင့်မြင့်လုပ်ဆောင်မှုများကို မြန်ဆန်စွာ ပြုလုပ်နိုင်သည်။

Prettify JSON

jq ရဲ့ basic features တွေထဲက တစ်ခုဖြစ်တဲ့ identity filter ကို ကြည့်ကျရအောင် …

 echo '{"fruit":{"name":"apple","color":"red","price":3.0}}' | jq '.'

ကျွန်ုပ်တို့သည် အသီးတစ်ခု၏ အမည်၊ အရောင်နှင့် စျေးနှုန်းကို ဖော်ပြထားသော ရိုးရှင်းသော JSON object ကို echo ပြုလုပ်ပြီး jq command သို့ pipe ထည့်ပေးပါသည်။ Filter ‘.’ သည် identity filter ဖြစ်ပြီး ဒေတာကို မပြောင်းလဲဘဲ ထားပါသည်။ jq သည် input ကို စီစစ်သောအခါ အတိအကျ တူညီသော JSON ကို output ထုတ်ပေးပါသည်၊ သို့သော် jq သည် JSON output ကို ပိုမိုဖတ်ရှုရလွယ်ကူအောင် အလိုအလျောက် "pretty-print" သို့မဟုတ် ဖော်မတ်လုပ်ပေးသည်။

JSON ဖိုင်တစ်ခုမှာ ဒီ filter ကို direct တန်း အသုံးပြုနိုင်ပါတယ်။

#To create fruit.json file as below.
echo '{"fruit":{"name":"apple","color":"red","price":3.0}}' > fruit.json

jq '.' fruit.json

The ability of prettify JSON သည် API များထံမှ data များကို ရယူရာတွင် clear and readable ပုံစံဖြင့် ပြသရန် အထူးအသုံးဝင်သည်။ curl ကိုအသုံးပြုပြီး simple API call တစ်ခုကို ခေါ်ကြည့်ကျရအောင်

curl http://api.open-notify.org/iss-now.json | jq '.'

၎င်းသည် နိုင်ငံတကာ အာကာသစခန်း (ISS) ၏ လက်ရှိအနေအထားကို ပြသသည့် JSON response ကို ပေးသည်။

Accessing Properties

JSON တည်ဆောက်ပုံအတွင်းရှိ သတ်မှတ်ထားတဲ့ values တွေကို .field operator လို့ခေါ်တဲ့ filter ကိုအသုံးပြုပြီး jq ဖြင့် ရယူနိုင်ပါတယ်။ ဒီ operator က JSON object ရဲ့ specific property or field တစ်ခုရဲ့ value ကို ရယူနိုင်စေပါတယ်။

fruit.json ရဲ့ example ကို ဆက်လက် အသုံးပြုပြီး ဒီအရာကို ကြည့်ကျရအောင် …

jq '.fruit' fruit.json

ဒီနေရာမှာ ကျွန်တော်တို့ fruit property ကို ရွေးပြီး၊ အဲဒီ property အောက်မှာပါတဲ့ အရာတွေကို တစ်ခုလုံး ပြသဖို့ လုပ်ပါတယ်။ fruit ဟာ အဓိက key ဖြစ်ပြီး၊ အဲ့ဒီ key အောက်မှာ name, color, price လို့ခေါ်တဲ့ အချက်အလက်တွေ (children) ပါပါတယ်။

{
  "name": "apple",
  "color": "red",
  "price": 3.0
}

ကျွန်တော်တို့ property တွေကို အဆင့်လိုက်ဆက်ပြီး ရှာဖွေသုံးနိုင်ပါတယ်။ ဒါကိုဆိုလိုတာက JSON အထဲမှာ အတွင်းပိုင်းရှိ (nested) အချက်အလက်တွေကို ရယူနိုင်တာပါ။ ဥပမာအားဖြင့် fruit property ရဲ့ name ကို ရယူချင်ရင် .fruit.name လို့ ရိုက်လိုက်ရုံနဲ့ ရနိုင်ပါတယ်။

jq '.fruit.color' fruit.json
jq '.fruit.nmae' fruit.json
jq '.fruit.price' fruit.json

JSON မှာ key တစ်ခုထက် ပိုပြီး ရယူချင်ရင် key တွေကို comma နဲ့ ခွဲပြီး ရယူနိုင်ပါတယ်။ ဥပမာ fruit အောက်မှာ color နဲ့ price တိုင်းကို ရယူချင်ရင် .fruit.color, .fruit.price လို့ ရိုက်နိုင်ပါတယ်။ Comma သုံးတာနဲ့ key နှစ်ခုလုံးရမှာ ဖြစ်ပါတယ်။

jq '.fruit.color,.fruit.price' fruit.json

အကယ်၍ JSON ထဲမှာ space ပါတဲ့ key ရှိခဲ့မယ်ဆိုရင်၊ အဲ့ဒီ key ကို ရိုးရိုး key တစ်ခုလို .key နဲ့ ချိတ်မရနိုင်ပါဘူး။ ဥပမာအားဖြင့် with space ဆိုတဲ့ key မှာ space တစ်ခု ပါပါတယ်။ အဲ့ဒီလို key ကို jq နဲ့ရယူချင်ရင်၊ အဲ့ဒီ key ကို double quotes (“”) အတွင်း ထည့်သုံးပေးရပါမယ်။

ပုံမှန် key တစ်ခုကို .key ဆိုပြီး ရယူနိုင်သလို၊ space ပါတဲ့ key ကို ."with space" ဆိုပြီး double quotes နဲ့ ရိုက်ပြီးသုံးရပါတယ်။

ဉပမာအားဖြင့် with_space.json ဖိုင်မှာ အောက်ပါအတိုင်း content ရှိခဲ့မယ်ဆိုပါစို့ …

{
  "regularKey": "value1",
  "with space": "value2",
  "123startWithNumber": "value3"
}

jq ကို အသုံးပြု၍ အဲ့ဒီ property တွေကို ရယူဖို့ …

aungaung@drlinuxer-x14:~$ jq '."regularKey"' with_space.json
"value1"
aungaung@drlinuxer-x14:~$ jq '."with space"' with_space.json
"value2"
aungaung@drlinuxer-x14:~$ jq '."123startWithNumber"' with_space.json
"value3"

What is a JSON Array?

JSON Array ဆိုသည်မှာ JSON တွင် အချက်အလက်များ၏ စာရင်းကို ကိုယ်စားပြုသည့် data structure တစ်ခုဖြစ်သည်။ Array ထဲတွင် ပါရှိသည့် အချက်အလက်များသည် strings၊ numbers၊ objects၊ arrays၊ booleans၊ သို့မဟုတ် null အပါအဝင် JSON မှာ အတည်ပြုထားသည့် data အမျိုးအစား မည်သည့်အရာမဆို ဖြစ်နိုင်ပါသည်။

JSON array များကို [] (square brackets) ဖြင့် ကန့်သတ်ထားပြီး၊ array အတွင်းရှိ item များကို comma (,) ဖြင့် ခွဲထားသည်။

JSON array ကို အမျိုးမျိုးသော data အမျိုးအစားတွေနဲ့ ဖော်ပြထားပါတယ်။

  1. Strings Array:
["apple", "banana", "cherry"]
  1. Numbers Array:
[1, 2, 3, 4.5, 6.78]
  1. Objects Array:
[
  {"name": "Alice", "age": 25},
  {"name": "Bob", "age": 30}
]
  1. Nested Arrays:
[[1, 2, 3], ["a", "b", "c"], [true, false]]
  1. Booleans Array:
[true, false, true, false]
  1. Nulls Array:
[null, null, "example", 42]

ဒီအကြောင်းအရာတွေက JSON array များကို မတူညီတဲ့ data type မျိုးစုံနဲ့ ဘယ်လိုဖွဲ့စည်းနိုင်တယ်ဆိုတာကို ပြသပေးပါတယ်။

jq ကိုသုံးပြီး အထက်ဖော်ပြခဲ့သည့် JSON array များကို ရယူရန် နှင့် စိစစ်ရန် အတွက် အောက်ပါနည်းလမ်းများကို အသုံးပြုနိုင်ပါတယ်။

  1. Strings Array:

     echo '["apple", "banana", "cherry"]' | jq '.[1]'
    

    Output: "banana"
    (Index 1 မှာရှိတဲ့ item ကို ရယူရန်)

  2. Numbers Array:

     echo '[1, 2, 3, 4.5, 6.78]' | jq '.[3]'
    

    Output: 4.5
    (Index 3 မှာရှိတဲ့ number ကို ရယူရန်)

  3. Objects Array:

     echo '[{"name": "Alice", "age": 25}, {"name": "Bob", "age": 30}]' | jq '.[0].name'
    

    Output: "Alice"
    (Index 0 မှာရှိတဲ့ object ရဲ့ name property ကို ရယူရန်)

  4. Nested Arrays:

     echo '[[1, 2, 3], ["a", "b", "c"], [true, false]]' | jq '.[1][2]'
    

    Output: "c"
    (Index 1 ရဲ့ nested array ထဲက Index 2 ကို ရယူရန်)

  5. Booleans Array:

     echo '[true, false, true, false]' | jq '.[2]'
    

    Output: true
    (Index 2 မှာရှိတဲ့ boolean value ကို ရယူရန်)

  6. Nulls Array:

     echo '[null, null, "example", 42]' | jq '.[2]'
    

    Output: "example"
    (Index 2 မှာရှိတဲ့ string ကို ရယူရန်)

ဒါ့အပြင် jq ကို အသုံးပြု၍ array ရဲ့ items များကို filter လုပ်ခြင်း၊ မိမိလိုအပ်သည့် conditions တွေ ဖြင့် ပြင်ဆင်ခြင်း စသဖြင့် ပိုမိုရှုပ်ထွေးတဲ့ လုပ်ဆောင်ချက်များကိုလည်း လုပ်ဆောင်နိုင်ပါတယ်။


Iterating Over a JSON Array

JSON array ထဲက item တစ်ခုချင်းစီကို loop ဖြင့် iterate (ပြန်လှည့်) သွားရန် jq ကို အသုံးပြုနိုင်ပါတယ်။ ဒါက JSON array ထဲမှာ item အပေါင်းကို အသီးအသီး ရယူပြီး လုပ်ဆောင်မှုတစ်ခုခု ပြုလုပ်ချင်တဲ့အခါအသုံးဝင်ပါတယ်။

ဥပမာအားဖြင့် JSON array ကို iterating လုပ်ပုံကို ပြသထားပါတယ်။

Iterating Over a JSON Array

Example 1: Iterating Over a Strings Array

echo '["apple", "banana", "cherry"]' | jq '.[]'

Output:

"apple"
"banana"
"cherry"

Explanation: jq '.[]' က JSON array ထဲက item တစ်ခုချင်းစီကို ရယူပြီး အစီအစဉ်အတိုင်း ပြသပေးပါတယ်။

Example 2: Iterating Over an Array of Numbers

echo '[1, 2, 3, 4.5, 6.78]' | jq '.[]'

Output:

1
2
3
4.5
6.78

Explanation: .[] က array ထဲက number တစ်ခုချင်းစီကို ပြသရန် အသုံးပြုသည်။

Example 3: Iterating Over an Array of Objects

echo '[{"name": "Alice", "age": 25}, {"name": "Bob", "age": 30}]' | jq '.[] | .name'

Output:

"Alice"
"Bob"

Explanation: .[] က object တစ်ခုချင်းစီကို iterate လုပ်ပြီး၊ | .name ကတော့ object ထဲက name property ကိုပြသဖို့ သတ်မှတ်ထားခြင်း ဖြစ်ပါတယ်။

Example 4: Iterating Over Nested Arrays

echo '[[1, 2, 3], ["a", "b", "c"], [true, false]]' | jq '.[] | .[1]'

Output:

2
"b"
false

Explanation: .[] | .[1] က array တစ်ခုချင်းစီကို iterate လုပ်ပြီး၊ array item တစ်ခုချင်းစီမှ index 1 ကို ရယူသည်။

Iterating Over with Additional Processing

echo '[true, false, null, "example"]' | jq '.[] | select(. != null)'

Output:

true
false
"example"

Explanation: select(. != null) က null မဟုတ်တဲ့ items တွေကိုသာ ရယူပြသရန် filter လုပ်ထားခြင်း ဖြစ်ပါတယ်။

ဒီလိုနည်းလမ်းတွေက JSON array ထဲမှာ item တွေကို loop ဖွင့်ပြီး iterate လုပ်ရုံသာမက၊ ထိန်းချုပ်နိုင်တဲ့ logic တွေကိုပါ ထည့်သွင်းသုံးစွဲနိုင်ပါတယ်။

One of the most common operations when working with JSON arrays is iterating over the items in the array. To do this in jq, we use the iterator operator .[]. This operator will iterate over each element in the array and return each one individually.

For example, if you have the array ["x", "y", "z"], you can iterate over it with:

echo '["x","y","z"]' | jq '.[]'

The .[] operator iterates over each element of the array, and jq prints each item on a separate line.

"x"
"y"
"z"

Working with Arrays of Objects

Let’s say we have an array where each element is an object instead of a simple value. For example, imagine we have an array of fruit objects, each containing information like the name, color, and price of a fruit:

vi fruit2.json
[
  {
    "name": "apple",
    "color": "red",
    "price": 3.0
  },
  {
    "name": "banana",
    "color": "yellow",
    "price": 2.0
  },
  {
    "name": "kiwi",
    "color": "green",
    "price": 1.5
  }
]

Each item in the array is an object with properties like name, color, and price.

Extracting Specific Values

If we want to extract the name of each fruit in the array, we would use the .[] operator to iterate over the array and then access the name property for each object. Here's the jq command to do that:

jq '.[] | .name' fruit2.json

First, we iterate over the array using .[]. Then we can pass each object in the array to the next filter in the command using a pipe |. The last step is to output the name field from each object using .name:

A More Concise Version

We can simplify this even further by combining both operations into one:

jq '.[].name' fruits.json


Accessing Array Items by Index in jq

In jq, you can access individual elements from an array by using indices (positions) in the array, similar to how you'd access an array element in most programming languages.

Example: Accessing by Index

Let’s assume we have the following array of fruit objects:

jq '.[0].price' fruit2.json
jq '.[1].price' fruit2.json
jq '.[2].price' fruit2.json


Slicing Arrays in jq

Slicing is a powerful feature that allows you to extract subarrays from an array. This is useful when you need only a portion of the array rather than the entire set of elements.

Example: Slicing an Array

Consider the following array of numbers:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Let’s say you want to get a subarray of elements starting from index 6 (inclusive) to index 9 (exclusive). You can use slicing as follows:

echo '[1,2,3,4,5,6,7,8,9,10]' | jq '.[6:9]'

Output:

[7, 8, 9]
  • .[6:9]: This slice starts at index 6 (inclusive) and ends at index 9 (exclusive). So, it includes the elements at indices 6, 7, and 8, which are 7, 8, and 9.

Omitting Indices in Slicing

In jq, you can also omit one or both of the indices in the slice to define a range starting from the beginning or going until the end of the array.

  1. Slice from the beginning to a specific index:
echo '[1,2,3,4,5,6,7,8,9,10]' | jq '.[:6]'

Output:

[1, 2, 3, 4, 5, 6]
  • [:6]: This slice means "start from the beginning" (index 0) and go up to but not including index 6. It returns the elements 1, 2, 3, 4, 5, 6.
  1. Slice from a negative index to the end:
echo '[1,2,3,4,5,6,7,8,9,10]' | jq '.[-2:]'

Output:

[9, 10]
  • .[-2:]: This slice starts from the second-to-last element (-2) and includes all elements up to the end of the array.

  • The negative index means it counts backwards from the end of the array. So, -2 refers to the element 9, and : means "continue until the end."

Combining Slices

You can also combine slices for more complex extraction.

For example:

echo '[1,2,3,4,5,6,7,8,9,10]' | jq '.[:6] | .[-2:]'

Output:

[5, 6]

Here’s what happens:

  • [:6]: This slice gives us the first 6 elements: [1, 2, 3, 4, 5, 6].

  • .[-2:]: The second slice (.[-2:]) selects the last two elements from that result, which are [5, 6].

Summary of Key Concepts:

  1. Accessing by Index: You can directly access an element in an array by specifying its index, using .[index].

    • For example, .[1].price accesses the second item in an array and retrieves the price field.
  2. Array Slicing: jq supports array slicing, which allows you to extract subarrays by specifying a start and end index in the form .[start:end].

    • You can omit the start ([:end]) or end ([start:]) to slice from the beginning or until the end, respectively.
  3. Negative Indices: Negative indices (like -2) count backwards from the end of the array, with -1 being the last element.

These features give you flexible ways to manipulate and access parts of arrays within JSON data using jq.


Using Functions in jq

jq provides many powerful built-in functions that allow you to manipulate, transform, and query JSON data efficiently. Here’s a breakdown of some useful functions:

1. Getting Keys

Sometimes, you might want to get just the keys of an object in JSON, rather than its values. You can use the keys function for this:

jq '.fruit | keys' fruit.json

This gives us the keys sorted alphabetically:

[
  "color",
  "name",
  "price"
]

2. Returning the Length

You can use the length function to get the length of an array or the number of properties in an object:

  • On an Object (getting the number of properties):

      jq '.fruit | length' fruit.json
    

    Output:

      3
    

    This shows that the fruit object has 3 properties (color, name, and price).

  • On a String (getting the length of a string):

      jq '.fruit.name | length' fruit.json
    

    Output:

      5
    

    This shows that the name of the fruit ("apple") has 5 characters.

3. Mapping Values with map

The map function applies a filter or transformation to each element in an array. For example, you can use it to check for the presence of a property in each object:

jq 'map(has("name"))' fruit2.json
  • This will check if the name property exists in each object in the array. If it does, it will return true; otherwise, false.

    Output:

      [
        true,
        true,
        true
      ]
    

You can also use map to apply a transformation to the values in the array, such as modifying the price:

jq 'map(.price + 2)' fruit2.json
  • This adds 2 to the price of each fruit.

    Output:

      [
        5,
        4,
        3.5
      ]
    

4. Min and Max Functions

To find the minimum or maximum value in an array, you can use the min and max functions:

  • Minimum Price:

      jq '[.[].price] | min' fruit2.json
    

    Output:

      1.5
    
  • Maximum Price:

      jq '[.[].price] | max' fruit2.json
    

    Output:

      3.0
    

In both cases, we construct a new array of just the price values using [.[].price] before applying min or max.

5. Selecting Values with select

The select function allows you to filter elements in an array based on certain conditions, similar to how XPath works for XML.

For example, you can select fruits with a price greater than 1.5:

jq '.[] | select(.price > 1.5)' fruit2.json
  • This selects all fruits with a price greater than 1.5.

    Output:

      {
        "name": "apple",
        "color": "red",
        "price": 3.0
      }
      {
        "name": "banana",
        "color": "yellow",
        "price": 2.0
      }
    

You can also combine conditions, like selecting fruits that are yellow and have a price greater than or equal to 1.5:

jq '.[] | select(.color == "yellow" and .price >= 1.5)' fruit2.json

Output:

{
  "name": "banana",
  "color": "yellow",
  "price": 2.0
}

6. Using Regular Expressions with test

The test function allows you to test if a string matches a regular expression. For example, to select fruits whose name starts with the letter "a":

jq '.[] | select(.name | test("^a.")) | .price' fruit2.json
  • This filters fruits where the name starts with "a" and returns their price.

    Output:

      3.0
    

7. Finding Unique Values with unique

To find unique values in an array, you can use the unique function. For example, to find all unique colors in the fruits.json:

jq 'map(.color) | unique' fruit2.json
  • The map(.color) part creates a new array with just the color values.

  • The unique function then removes duplicates.

    Output:

      [
        "green",
        "red",
        "yellow"
      ]
    

8. Deleting Keys with del

The del function allows you to remove a key from a JSON object. For example, if you want to delete the name property from the fruit object:

jq 'del(.fruit.name)' fruit.json
  • This will remove the name key and its corresponding value.

    Output:

      {
        "fruit": {
          "color": "red",
          "price": 3.0
        }
      }
    

9. Transforming JSON Structure

You can also transform the structure of your JSON. For example, suppose you have JSON data from Wikipedia pages, and you want to extract only the title and extract fields for each page:

vi transform.json
{
  "query": {
    "pages": [
      {
        "21721050": {
          "pageid": 21721050,
          "ns": 0,
          "title": "Stack Overflow",
          "extract": "Some interesting text about Stack Overflow"
        }
      },
      {
        "21721051": {
          "pageid": 21721051,
          "ns": 0,
          "title": "Github",
          "extract": "Build software better, together"
        }
      }
    ]
  }
}

To transform this JSON into a new structure containing only the title and extract fields:

jq '.query.pages | [.[] | map(.) | .[] | {page_title: .title, page_description: .extract}]' transform.json
  • This creates a new array of objects with just the title and extract properties.

    Output:

      [
        {
          "page_title": "Stack Overflow",
          "page_description": "Some interesting text about Stack Overflow"
        },
        {
          "page_title": "Github",
          "page_description": "Build software better, together"
        }
      ]
    

Summary

These are just a few examples of the many powerful functions available in jq. These functions enable you to:

  • Extract keys and values.

  • Perform filtering and selection.

  • Modify arrays and objects.

  • Apply transformations to JSON data.

By combining these functions, you can perform complex operations and data manipulations directly on JSON, making jq a powerful tool for working with structured data.