تحويل كائنات JSON وإنشاؤها باستخدام jq
أعد تشكيل البيانات باستخدام map وto_entries وإنشاء الكائنات لإنتاج حمولات JSON جديدة
تحويل كائنات JSON وإنشاؤها باستخدام jq درس مجاني في DevOps Bootcamp على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في DevOps Bootcamp، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة DevOps Bootcamp 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_entriesto_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_casemap(.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 ما يلي:
- تصفية مصفوفة الإدخال باستخدام
map(select(...)) - إعادة تشكيل كل عنصر بإنشاء كائن
- إضافة حقول محسوبة
- فرز الناتج
يقرأ المثال التالي قائمة بمقاييس الخوادم، ويحتفظ فقط بالخوادم ذات الاستخدام المرتفع لوحدة المعالجة المركزية، وينتج حمولة تنبيه مختصرة جاهزة لإرسالها عبر 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) وفتح باقي دورة DevOps Bootcamp، انتقل إلى CoddyKit PRO. تتضمن دورة DevOps Bootcamp 4 دروس في المجموع.
ماذا ستتعلم في «تحويل كائنات JSON وإنشاؤها باستخدام jq»؟
أعد تشكيل البيانات باستخدام map وto_entries وإنشاء الكائنات لإنتاج حمولات JSON جديدة تتمرن على DevOps Bootcamp مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ DevOps Bootcamp؟
لا تُشترط خبرة سابقة. DevOps Bootcamp على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «تحويل كائنات JSON وإنشاؤها باستخدام jq»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس DevOps Bootcamp هذا؟
نعم. كل درس في DevOps Bootcamp يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- تصفية JSON وتحديد عناصره باستخدام مسارات jq
- تحويل كائنات JSON وإنشاؤها باستخدام jq
- استهلاك REST APIs باستخدام curl وjq معًا
- تحرير ملفات إعداد YAML باستخدام yq