0Pricing
Linux Command Line & Bash Scripting Mastery · درس

تحويل كائنات JSON وإنشاؤها باستخدام jq

أعد تشكيل البيانات باستخدام map وto_entries وإنشاء الكائنات لإنتاج حمولات JSON جديدة

تحويل كائنات JSON وإنشاؤها باستخدام jq درس مجاني في Linux Command Line & Bash Scripting Mastery على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Linux Command Line & Bash Scripting Mastery، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Linux Command Line & Bash Scripting Mastery 4 دروس في المجموع.

لماذا نحول JSON؟

نادراً ما تكون بنية JSON الخام الواردة من واجهات API أو ملفات السجل مطابقة تمامًا للبنية التي تحتاجون إليها. فقد تتلقون كائنًا كبيرًا بينما لا تريدون سوى حقول محددة، أو قد تحتاجون إلى إعادة تسمية المفاتيح أو تسطيح الهياكل المتداخلة أو إنشاء حمولة جديدة تمامًا لإرسالها إلى خدمة أخرى.

jq معالج خفيف وقوي لـ JSON من سطر الأوامر، يتيح إجراء هذه التحويلات في مسار واحد. في هذا الدرس ستتعلمون التقنيات الأساسية الثلاث لإعادة تشكيل البيانات:

  • إنشاء الكائنات — بناء كائن JSON جديد من الصفر
  • map — تطبيق تحويل على كل عنصر في مصفوفة
  • to_entries / from_entries — التعامل مع أزواج مفاتيح وقيم الكائن كمصفوفة، بحيث يمكن تصفيتها وإعادة بنائها

تفترض جميع الأمثلة تثبيت jq (apt install jq / brew install jq).

أساسيات إنشاء الكائنات

أهم ميزات jq الأساسية هي إنشاء الكائنات: إحاطة التعبيرات بـ {} لبناء كائن JSON جديد. يمكنكم اختيار الحقول التي تريدون تضمينها وتحديد أسمائها.

الصياغة:

  • { newKey: .existingField } — إعادة تسمية حقل
  • { name, age } — صياغة مختصرة عندما يطابق المفتاح الجديد اسم الحقل
  • { total: (.price * .qty) } — حساب قيمة ضمن التعبير مباشرة

يقرأ المقطع التالي بيانات JSON لمنتج وينتج بنية أكثر اختصارًا تحتوي على حقل subtotal محسوب.

#!/usr/bin/env bash
# Object construction: pick and rename fields
product='{
  "id": 42,
  "name": "Widget Pro",
  "price": 9.99,
  "qty": 3,
  "warehouse": "EU-West"
}'

echo "$product" | jq '{
  productId: .id,
  name,
  subtotal: (.price * .qty)
}'

إنشاء كائنات من بيانات متداخلة

غالبًا ما تكون بيانات JSON الواقعية متداخلة. يتيح لكم jq الوصول إلى المسارات المتداخلة داخل مُنشئ الكائن، مع تسطيح البنية في الوقت نفسه.

استخدموا ترميز المسار النقطي داخل تعبير قيمة المُنشئ:

  • { city: .address.city }
  • { lat: .location.coords.lat }

يأخذ المثال التالي سجل مستخدم متداخلًا بعمق وينتج ملخصًا مسطحًا مناسبًا لصف عناوين CSV أو لنص طلب إلى API.

#!/usr/bin/env bash
user='{
  "id": "u-001",
  "profile": {
    "displayName": "Ada Lovelace",
    "contact": { "email": "ada@example.com", "phone": "+44-700" }
  },
  "plan": "pro"
}'

echo "$user" | jq '{
  id,
  name: .profile.displayName,
  email: .profile.contact.email,
  plan
}'

تحويل المصفوفات باستخدام map

تُعد map(expr) النظير في jq للحلقة for-each؛ فهي تطبق expr على كل عنصر في مصفوفة الإدخال وتعيد مصفوفة جديدة بالطول نفسه.

النقاط الأساسية:

  • map(expr) صياغة مختصرة لـ [.[] | expr]
  • يمكن أن يكون التعبير الداخلي أي عامل تصفية في jq — بما في ذلك إنشاء الكائنات
  • يمكن ربطها مع select() للتصفية قبل التحويل

يعالج المقطع قائمة من الطلبات، مع الاحتفاظ بالحقول المطلوبة فقط في بيان الشحن.

#!/usr/bin/env bash
orders='[
  {"orderId": 1, "customer": "Alice", "total": 42.50, "status": "shipped"},
  {"orderId": 2, "customer": "Bob",   "total": 18.00, "status": "pending"},
  {"orderId": 3, "customer": "Carol", "total": 99.99, "status": "shipped"}
]'

# Produce a shipping manifest: only shipped orders, slim fields
echo "$orders" | jq '[
  .[] | select(.status == "shipped") | {
    id: .orderId,
    recipient: .customer,
    amount: .total
  }
]'

استخدام map مع الحقول المحسوبة

يمكنكم داخل map حساب قيم جديدة وتحويل الأنواع ودمج الحقول — وليس نسخها فقط. ومن الأنماط الشائعة:

  • إقحام النصوص: "\(.first) \(.last)"
  • الحساب: (.price * 1.2 | round) لزيادة السعر بنسبة 20%
  • الشروط: if .score >= 90 then "A" else "B" end

يثري المثال التالي قائمة الموظفين بإضافة fullName محسوب وتصنيف seniority استنادًا إلى سنوات الخبرة.

#!/usr/bin/env bash
staff='[
  {"first": "Grace", "last": "Hopper",  "years": 15},
  {"first": "Alan",  "last": "Turing",  "years": 4},
  {"first": "Linus", "last": "Torvalds","years": 9}
]'

echo "$staff" | jq 'map({
  fullName: "\(.first) \(.last)",
  years,
  seniority: (if .years >= 10 then "senior" elif .years >= 5 then "mid" else "junior" end)
})'

فهم to_entries

تحوّل to_entries كائن JSON إلى مصفوفة من أزواج {key, value}. ويتيح ذلك استخدام عمليات المصفوفات (map وselect وsort) على حقول الكائن، وهو ما لا يمكن إجراؤه مباشرةً على كائن.

مثال على التحويل:

  • الإدخال: {"a": 1, "b": 2}
  • الإخراج: [{"key": "a", "value": 1}, {"key": "b", "value": 2}]

العملية العكسية هي from_entries، التي تحول تلك المصفوفة مرة أخرى إلى كائن. وتشكل العمليتان معًا النمط to_entries | map(...) | from_entries لإجراء التحويلات على مستوى الكائن.

#!/usr/bin/env bash
# Demonstrate to_entries and from_entries
config='{"host": "db.local", "port": 5432, "ssl": true}'

echo "--- to_entries output ---"
echo "$config" | jq 'to_entries'

echo "--- round-trip back to object ---"
echo "$config" | jq 'to_entries | from_entries'

تصفية المفاتيح باستخدام to_entries

من أكثر استخدامات to_entries عمليةً تصفية المفاتيح التي يجب الاحتفاظ بها أو حذفها ديناميكيًا استنادًا إلى اسم المفتاح نفسه — وهو أمر لا يمكن لإنشاء الكائنات تنفيذه عندما لا تعرفون أسماء المفاتيح مسبقًا.

النمط:

  • to_entries | map(select(.key | test("regex"))) | from_entries
  • to_entries | map(select(.key != "secret")) | from_entries

يزيل المقطع التالي جميع المفاتيح التي تبدأ بشرطة سفلية (الحقول الداخلية/الخاصة) قبل تمرير كائن الإعدادات إلى خدمة خارجية.

#!/usr/bin/env bash
raw_config='{
  "endpoint": "https://api.example.com",
  "timeout": 30,
  "_internalToken": "s3cr3t",
  "_debugMode": true,
  "retries": 3
}'

# Remove any key starting with underscore
echo "$raw_config" | jq '
  to_entries
  | map(select(.key | startswith("_") | not))
  | from_entries
'

إعادة تسمية المفاتيح ديناميكيًا باستخدام to_entries

تتيح لكم عملية إنشاء الكائنات إعادة تسمية المفاتيح عندما تعرفون أسماءها وقت الكتابة. أما to_entries فتتيح إعادة تسمية المفاتيح برمجيًا — مثل تحويل camelCase إلى snake_case أو إضافة بادئة.

داخل map، حدّثوا الحقل .key لكل إدخال، ثم مرروا الناتج إلى from_entries:

  • map(.key |= gsub("(?<=[a-z])(?=[A-Z])"; "_") | .key |= ascii_downcase) — تحويل camelCase إلى snake_case
  • map(.key |= "app_" + .) — إضافة بادئة إلى كل مفتاح

يضيف المثال البادئة APP_ إلى جميع أسماء متغيرات البيئة لتحديد نطاقها قبل حقنها في حاوية.

#!/usr/bin/env bash
env_vars='{"host": "localhost", "port": "8080", "debug": "false"}'

# Add APP_ prefix and uppercase all keys
echo "$env_vars" | jq '
  to_entries
  | map({ key: ("APP_" + (.key | ascii_upcase)), value })
  | from_entries
'

with_entries: الصياغة المختصرة الملائمة

إن النمط to_entries | map(...) | from_entries شائع جدًا، لذلك يوفر jq صياغة مختصرة له: with_entries(expr).

وهو مكافئ تمامًا، لكنه أكثر إيجازًا:

  • with_entries(.value |= . * 2) — مضاعفة كل قيمة رقمية
  • with_entries(select(.value != null)) — حذف المفاتيح ذات القيم الفارغة
  • with_entries(.key |= ascii_upcase) — تحويل جميع المفاتيح إلى أحرف كبيرة

يزيل المقطع جميع المفاتيح التي تكون قيمتها null أو سلسلة فارغة — وهي خطوة تنظيف شائعة قبل إرسال طلب PATCH إلى REST API.

#!/usr/bin/env bash
patch_body='{
  "name": "Mehmet",
  "email": "",
  "phone": null,
  "city": "Istanbul"
}'

# Drop empty/null fields before PATCH
cleaned=$(echo "$patch_body" | jq '
  with_entries(select(.value != null and .value != ""))
')

echo "Cleaned payload:"
echo "$cleaned"

# In practice you would pipe to curl:
# curl -s -X PATCH https://api.example.com/users/1 \
#   -H "Content-Type: application/json" \
#   -d "$cleaned"

دمج map وإنشاء الكائنات في مسار واحد

تربط التحويلات الواقعية عدة عمليات jq معًا. وقد يتضمن المسار المعتاد لإعداد حمولة API ما يلي:

  1. تصفية مصفوفة الإدخال باستخدام map(select(...))
  2. إعادة تشكيل كل عنصر بإنشاء كائن
  3. إضافة حقول محسوبة
  4. فرز الناتج

يقرأ المثال التالي قائمة بمقاييس الخوادم، ويحتفظ فقط بالخوادم ذات الاستخدام المرتفع لوحدة المعالجة المركزية، وينتج حمولة تنبيه مختصرة جاهزة لإرسالها عبر POST إلى webhook.

#!/usr/bin/env bash
metrics='[
  {"host": "web-01", "cpu": 23, "mem": 60, "region": "eu"},
  {"host": "web-02", "cpu": 91, "mem": 88, "region": "eu"},
  {"host": "db-01",  "cpu": 78, "mem": 95, "region": "us"},
  {"host": "db-02",  "cpu": 12, "mem": 40, "region": "us"}
]'

alerts=$(echo "$metrics" | jq '[
  .[] | select(.cpu > 75 or .mem > 85) | {
    server: .host,
    region,
    severity: (if .cpu > 90 or .mem > 90 then "critical" else "warning" end),
    metrics: { cpu: .cpu, mem: .mem }
  }
] | sort_by(.severity)')

echo "$alerts"

إنشاء كائن JSON جديد من مصادر متعددة

يمكن لـ jq دمج المدخلات وإنشاء كائنات تستمد بياناتها من مصادر JSON متعددة باستخدام عامل الجمع + وربط المتغيرات باستخدام as $var.

أنماط مفيدة:

  • obj1 + obj2 — دمج كائنين (تسود قيم الطرف الأيمن عند تعارض المفاتيح)
  • --argjson — تمرير مستند JSON ثانٍ كمتغير
  • $ENV — قراءة متغيرات البيئة مباشرةً داخل jq

يدمج المقطع إعدادًا أساسيًا مع تجاوزات خاصة بالبيئة — وهو نمط شائع لإدارة إعدادات التطبيقات وفق منهجية 12-factor في نصوص الصدفة.

#!/usr/bin/env bash
base_config='{
  "logLevel": "info",
  "timeout": 30,
  "retries": 3,
  "database": "postgres://db.local/app"
}'

env_overrides='{
  "logLevel": "debug",
  "database": "postgres://db.staging/app_staging"
}'

# Merge: overrides win on conflicts
merged=$(echo "$base_config" | jq --argjson overrides "$env_overrides" '. + $overrides')

echo "Merged config:"
echo "$merged"

اختبار المعرفة: to_entries مقارنةً بـ map

لديكم كائن JSON التالي، وتحتاجون إلى إزالة جميع المفاتيح التي تقل قيمتها عن 0، لإنتاج كائن جديد يحتوي على القيم غير السالبة فقط. ما تعبير jq الذي يحقق ذلك بصورة صحيحة؟

الإدخال: {"a": 10, "b": -3, "c": 0, "d": 5}

مراجعة الدرس: تحويل JSON باستخدام jq

لقد تناولتم التقنيات الأساسية لإعادة تشكيل JSON باستخدام jq:

  • إنشاء الكائنات {} — بناء كائنات جديدة عبر اختيار الحقول وإعادة تسميتها وحسابها من الإدخال
  • map(expr) — تطبيق أي تحويل على كل عنصر في مصفوفة، بما في ذلك إنشاء الكائنات المتداخلة واستخدام select() للتصفية
  • to_entries / from_entries — تحويل كائن إلى مصفوفة من أزواج {key, value}، مما يتيح إجراء عمليات المصفوفات على المفاتيح والقيم، ثم تحويلها مرة أخرى
  • with_entries(expr) — الصياغة المختصرة لمسار to_entries → map → from_entries الكامل
  • دمج الكائنات باستخدام + و--argjson للحمولات متعددة المصادر

يمكن تركيب هذه اللبنات معًا: صفّوا باستخدام select، وأعيدوا التشكيل بإنشاء الكائنات، وأثروا البيانات بالحقول المحسوبة، واربطوا كل ذلك في تعبير jq واحد واضح. ويعني إتقان هذه الأنماط أنكم قادرون على معالجة أي حمولة JSON تقريبًا مباشرةً في الصدفة، من دون كتابة نص برمجي مخصص بلغة Python أو Node.

الأسئلة الشائعة

هل درس «تحويل كائنات JSON وإنشاؤها باستخدام jq» مجاني؟

نعم — نص درس «تحويل كائنات JSON وإنشاؤها باستخدام jq» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Linux Command Line & Bash Scripting Mastery، انتقل إلى CoddyKit PRO. تتضمن دورة Linux Command Line & Bash Scripting Mastery 4 دروس في المجموع.

ماذا ستتعلم في «تحويل كائنات JSON وإنشاؤها باستخدام jq»؟

أعد تشكيل البيانات باستخدام map وto_entries وإنشاء الكائنات لإنتاج حمولات JSON جديدة تتمرن على Linux Command Line & Bash Scripting Mastery مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Linux Command Line & Bash Scripting Mastery؟

لا تُشترط خبرة سابقة. Linux Command Line & Bash Scripting Mastery على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «تحويل كائنات JSON وإنشاؤها باستخدام jq»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Linux Command Line & Bash Scripting Mastery هذا؟

نعم. كل درس في Linux Command Line & Bash Scripting Mastery يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. تصفية JSON وتحديد عناصره باستخدام مسارات jq
  2. تحويل كائنات JSON وإنشاؤها باستخدام jq
  3. استهلاك REST APIs باستخدام curl وjq معًا
  4. تحرير ملفات إعداد YAML باستخدام yq
← العودة إلى Linux Command Line & Bash Scripting Mastery