Jq के साथ आंतरिक सरणी में मूल्यों के आधार पर वस्तुओं की एक सरणी को कैसे फ़िल्टर करें?


239

इस इनपुट को देखते हुए:

[
  {
    "Id": "cb94e7a42732b598ad18a8f27454a886c1aa8bbba6167646d8f064cd86191e2b",
    "Names": [
      "condescending_jones",
      "loving_hoover"
    ]
  },
  {
    "Id": "186db739b7509eb0114a09e14bcd16bf637019860d23c4fc20e98cbe068b55aa",
    "Names": [
      "foo_data"
    ]
  },
  {
    "Id": "a4b7e6f5752d8dcb906a5901f7ab82e403b9dff4eaaeebea767a04bac4aada19",
    "Names": [
      "jovial_wozniak"
    ]
  },
  {
    "Id": "76b71c496556912012c20dc3cbd37a54a1f05bffad3d5e92466900a003fbb623",
    "Names": [
      "bar_data"
    ]
  }
]

मैं jq के साथ एक फिल्टर का निर्माण करने की कोशिश कर रहा हूं जो सभी वस्तुओं को Idएस के साथ लौटाता है जिसमें आंतरिक सरणी में "डेटा" नहीं होता है Names, जिसमें आउटपुट न्यूलाइन-अलग होता है। उपरोक्त डेटा के लिए, मुझे जो आउटपुट चाहिए वह है

cb94e7a42732b598ad18a8f27454a886c1aa8bbba6167646d8f064cd86191e2b
a4b7e6f5752d8dcb906a5901f7ab82e403b9dff4eaaeebea767a04bac4aada19

मुझे लगता है कि मैं इसके साथ कुछ करीब हूं:

(. - select(.Names[] contains("data"))) | .[] .Id

लेकिन selectफ़िल्टर सही नहीं है और यह संकलन (प्राप्त error: syntax error, unexpected IDENT) नहीं करता है ।

जवाबों:


372

बहुत करीब! आपकी selectअभिव्यक्ति में, आपको |पहले एक पाइप ( ) का उपयोग करना होगा contains

यह फ़िल्टर अपेक्षित आउटपुट का उत्पादन करता है।

. - map(select(.Names[] | contains ("data"))) | .[] .Id

JQ कुकबुक वाक्य रचना का एक उदाहरण है।

एक कुंजी की सामग्री के आधार पर वस्तुओं को फ़िल्टर करें

उदाहरण के लिए, मैं केवल उन वस्तुओं को चाहता हूं, जिनकी शैली कुंजी में "घर" है।

$ json='[{"genre":"deep house"}, {"genre": "progressive house"}, {"genre": "dubstep"}]'
$ echo "$json" | jq -c '.[] | select(.genre | contains("house"))'
{"genre":"deep house"}
{"genre":"progressive house"}

कॉलिन डी पूछता है कि सरणी के JSON संरचना को कैसे संरक्षित किया जाए, ताकि अंतिम आउटपुट JSON ऑब्जेक्ट की एक धारा के बजाय एक एकल JSON सरणी हो।

सबसे आसान तरीका एक सरणी कंस्ट्रक्टर में पूरी अभिव्यक्ति को लपेटना है:

$ echo "$json" | jq -c '[ .[] | select( .genre | contains("house")) ]'
[{"genre":"deep house"},{"genre":"progressive house"}]

आप मानचित्र फ़ंक्शन का उपयोग भी कर सकते हैं:

$ echo "$json" | jq -c 'map(select(.genre | contains("house")))'
[{"genre":"deep house"},{"genre":"progressive house"}]

नक्शा इनपुट सरणी को खोल देता है, हर तत्व के लिए फ़िल्टर लागू करता है, और एक नया सरणी बनाता है। दूसरे शब्दों में, map(f)के बराबर है [.[]|f]


धन्यवाद, बढ़िया काम करता है! मैंने वास्तव में उस उदाहरण को देखा था, मैं इसे अपने परिदृश्य में ढालने में असफल रहा था :-)
अबे वोल्केर

1
वहाँ "सरणी के जसन संरचना को संरक्षित करने के लिए" वैसे भी है? मुझे शैली का उदाहरण पसंद है लेकिन यह दो "json लाइन्स" को आउटपुट करता है। मैं जरूरी नक्शा भाग का पता नहीं लगा सका
कॉलिन डी

4
@ColinD मैं वास्तव में कम समाधान से खुश नहीं था, इसलिए मैंने इसे मैप फ़ंक्शन के स्पष्टीकरण के साथ बदल दिया। क्या उससे मदद हुई?
इयान सैमुअल मैकलीन एल्डर

@ आईनएदर - जब खोज शब्द का हिस्सा (इस मामले में घर) एक चर होता है तो क्या होता है? तो कहते हैं - शब्द का उपयोग करें। तो इसमें ("हौ $ टर्म") शामिल है
SnazzyBootMan

@ क्रिस वैरिएबल $termको एक स्ट्रिंग के रूप में माना जाता है, इसलिए आपको स्ट्रिंग कॉन्सेप्टन का उपयोग करना चाहिए:contains("hou" + $term)
इयान सैमुअल मैक्लीन एल्डर

17

यहां एक और समाधान है जो किसी भी / 2 का उपयोग करता है

map(select(any(.Names[]; contains("data"))|not)|.Id)[]

नमूना डेटा और -rविकल्प के साथ यह पैदा करता है

cb94e7a42732b598ad18a8f27454a886c1aa8bbba6167646d8f064cd86191e2b
a4b7e6f5752d8dcb906a5901f7ab82e403b9dff4eaaeebea767a04bac4aada19

बिल्कुल वही जो मैं ढूंढ रहा था - यह अर्ध-बृहदान्त्र के साथ काम क्यों करता है .Names[] ; contains()और पाइप के साथ नहीं .Names[] | contains()?
मैट

3
आह, यह any(generator; condition)रूप है। मैंने पाया कि any()अगर मैं select()एक ही वस्तु पर एक से अधिक बार मिलान करता हूं तो मैं अपने परिणामों में डुप्लिकेट के साथ समाप्त हो जाएगा ।
मैट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.