شی

شیء در jq

4 تمرین

درباره‌ی شیء

یک شیء JSON، با استفاده از اصطلاحات زبان‌های دیگر، همان «هش»، «نقشه» یا «دیکشنری» است.

JSON یک شیء را این‌گونه تعریف می‌کند:

یک شیء مجموعه‌ای نامرتب از جفت‌های اسم/مقدار است. یک شیء با { آکولاد باز شروع می‌شود و با } آکولاد بسته پایان می‌یابد. پس از هر اسم یک : دونقطه می‌آید و جفت‌های اسم/مقدار با , ویرگول از هم جدا می‌شوند.

اسم باید یک رشته باشد. واژه‌ی دیگری برای اسم، کلید است.

مقدار می‌تواند از هر نوع JSON باشد. مقدارهای مختلف در یک شیء واحد می‌توانند از انواع متفاوتی باشند، مثل این مثال.

{
  "name": "Jane",
  "age": 42,
  "pets": ["cat", "fish"],
  "address": {"street": "123 Main St", "city": "Springfield"}
}

توجه داشته باشید که پس از آخرین جفت کلید-مقدار نباید ویرگولی بیاید.

ساختن شیءها

از آکولاد برای جمع‌کردن جفت‌های اسم/مقدار استفاده کنید. با اینکه اسم‌ها باید رشته باشند، اگر شبیه شناسه باشند نیازی نیست داخل علامت نقل‌قول بگذاریدشان (یعنی از حروف و ارقام و زیرخط تشکیل شده باشند و با رقم شروع نشوند).

{name: "Jane", age: 42}

استفاده از کلیدهایی که شبیه شناسه نیستند هم مجاز است. فقط کافی است داخل علامت نقل‌قول بگذاریدشان.

{"first name": "Jane", "last name": "Lopez", age: 42}

اگر اسم حاصل یک عبارت باشد، آن عبارت باید داخل پرانتز قرار بگیرد.

$ echo "Jane" | jq -Rc '{.: 42}'
jq: error: syntax error, unexpected '.' (Unix shell quoting issues?) at <top-level>, line 1:
{.: 42}
jq: error: May need parentheses around object key expression at <top-level>, line 1:
{.: 42}
jq: 2 compile errors

$ echo "Jane" | jq -Rc '{(.): 42}'
{"Jane":42}

شکل‌های کوتاه‌نویسی

چند مورد پرتکرار در ساختن شیء شکل کوتاه‌نویسی دارند.

  1. استفاده‌ی دوباره از جفت‌های کلید-مقدار یک شیء ورودی.

    $ jq -n '$ENV | {USER: .USER, EDITOR: .EDITOR}'
    {
      "USER": "glennj",
      "EDITOR": "vim"
    }
    

    $ENV شیئی است که جفت‌های اسم-مقدار محیط را در خود نگه می‌دارد.

    جفت‌های تکراری key: .key را می‌توان فقط به شکل key نوشت

    $ jq -n '$ENV | {USER, EDITOR}'
    {
      "USER": "glennj",
      "EDITOR": "vim"
    }
    
  2. به همین شکل، هنگام استفاده از متغیرها هم یک کوتاه‌نویسی وجود دارد.

    $ jq -cn '"foo" as $a | "bar" as $b | {a: $a, b: $b}'
    {"a":"foo","b":"bar"}
    
    $ jq -cn '"foo" as $a | "bar" as $b | {$a, $b}'
    {"a":"foo","b":"bar"}
    

اندیس‌گذاری

مقادیر با نشانه‌گذاری با نقطه از یک شیء بازیابی می‌شوند.

{name: "Jane", age: 42} | .age    # => 42

اگر نمی‌توانید به کلید با یک شناسه ارجاع دهید، از نشانه‌گذاری با کروشه استفاده کنید.

"name" as $key | {name: "Jane", age: 42} | .$key    # => error
"name" as $key | {name: "Jane", age: 42} | .[$key]  # => "Jane"

اگر کلید در شیء نباشد، نتیجه null است.

{name: "Jane", age: 42} | .sport  # => null

اندیس‌گذاری مقدارهای تودرتو

خواهید دید که هنگام تجزیه‌ی نتیجه‌های پرس‌وجوهای API، این کاری است که باید بارها و بارها انجام دهید.

با داشتن شیئی که مقدارهای آرایه‌ای یا شیئی دارد، می‌توانیم عبارت‌های اندیس را به هم «زنجیر» کنیم.

{
  "name": "Jane",
  "age": 42,
  "pets": ["cat", "fish"],
  "address": {"street": "123 Main St", "city": "Springfield"}
}
| (
  .pets[1],       # => "fish"
  .address.city   # => "Springfield"
)

افزودن یا تغییر جفت‌های کلید-مقدار

برای افزودن یک جفت کلید-مقدار تازه به یک شیء، یا به‌روزرسانی مقدار یک کلید موجود، از عملگر انتساب = استفاده کنید و یک عبارت اندیس در سمت چپ قرار دهید.

{name: "Jane", age: 42} | .sport = "tennis" | .age = 21
# => {
#      "name": "Jane",
#      "age": 21,
#      "sport": "tennis"
#    }

عملگر + شیءها را ادغام می‌کند.

{Richard: 54} + {Jane: 42}
# => {
#      "Richard": 54,
#      "Jane": 42
#    }

حذف یک کلید

برای حذف یک کلید از تابع del استفاده کنید. این تابع شیء به‌روزشده را برمی‌گرداند.

{name: "Jane", age: 42} | del(.age)   # => {"name": "Jane"}

پارامتر del یک عبارت اندیس است (با نشانه‌گذاری نقطه یا کروشه) که به یک کلید در شیء اشاره می‌کند. jq به آن عبارت مسیر می‌گوید. صرفاً دادن یک رشته کافی نیست.

{name: "Jane", age: 42} | del(name)        # error: name/0 is not defined
{name: "Jane", age: 42} | del("name")      # error: Invalid path expression with result "name"
{name: "Jane", age: 42} | del(.name)       # OK
{name: "Jane", age: 42} | del(.["name"])   # OK

عضویت

  • برای بررسی اینکه آیا شیء یک کلید دارد، از تابع has استفاده کنید.

    {name: "Jane", age: 42} as $example
    |
      ($example | has("name")),    # => true
      ($example | has("sport"))    # => false
    
  • با in بررسی کنید که آیا کلیدی در شیء هست.

    {name: "Jane", age: 42} as $example
    |
      ("name"  | in($example)),    # => true
      ("sport" | in($example))     # => false
    

فهرست کردن کلیدها یا مقدارها

برای خروجی‌گرفتن فهرستی از همه‌ی کلیدها، از تابع keys استفاده کنید.

{name: "Jane", age: 42} | keys   # => ["age", "name"]

توجه کنید که keys کلیدها را مرتب می‌کند. برای بازیابی کلیدها به ترتیب اصلی، از keys_unsorted استفاده کنید.

هیچ تابع معادلی برای فهرست کردن همه‌ی مقدارها وجود ندارد. اما فیلتر .[] مقدارهای شیء را به‌صورت یک جریان خروجی می‌دهد و آن جریان را می‌توان با سازنده‌ی آرایه‌ی [...] ثبت کرد.

[{first: "Jane", last: "Lopez", status: "awesome!"} | .[]]
# => ["Jane", "Lopez", "awesome!"]

پیمایش

  • تابع map_values(filter) فیلتر را روی هر مقدار در شیء اعمال می‌کند.

    {first: "Jane", last: "Lopez", status: "awesome!"}
    | map_values(ascii_upcase)
    # => {"first": "JANE", "last": "LOPEZ", "status": "AWESOME!"}
    
  • برای پیمایش روی یک شیء، ابتدا باید آن را به آرایه‌ای از شیءهای کلید-مقدار تبدیل کنیم. تابع to_entries این کار را انجام می‌دهد.

    {name: "Jane", age: 42} | to_entries
    # => [
    #      {
    #        "key": "name",
    #        "value": "Jane"
    #      },
    #      {
    #        "key": "age",
    #        "value": 42
    #      }
    #    ]
    

    در این مرحله می‌توانیم از توابع پیمایش آرایه، مثل map، استفاده کنیم.

  • تابع from_entries برعکس این کار است: آرایه‌ای از شیءهای کلید-مقدار را به یک شیء تبدیل می‌کند.

    [
      {"key":"name", "value":"Jane"},
      {"key":"age", "value":42}
    ] | from_entries                  # => {"name": "Jane", "age": 42}
    
  • برای اعمال فیلتر روی هر جفت کلید-مقدار در یک شیء، از تابع with_entries(filter) استفاده کنید.

    برای مثال، با داشتن شیئی که اسمی را به یک سن نگاشت می‌کند، می‌توان کلیدها و مقدارها را به این شکل جابه‌جا کرد.

    {"Jane": 42, "Richard": 54}
    | with_entries({key: (.value | tostring), value: .key})
    

    خروجی می‌دهد

    {
      "42": "Jane",
      "54": "Richard"
    }
    

    with_entries(filter) همانند این است:

    to_entries | map(filter) | from_entries
    
ویرایش از طریق GitHub این پیوند در پنجره یا زبانه‌ی جدیدی باز می‌شود

شیء را یاد بگیرید

تمرین کردن قفل شده است

برای تمرین شیء قفل 4 تمرین دیگر را باز کنید