2016-06-30 11 views
11

Tôi thích để lọc file json sử dụng jq:Làm thế nào để lọc mảng các đối tượng theo giá trị thuộc tính phần tử bằng cách sử dụng jq?

jq . some.json 

Với json chứa một mảng của các đối tượng:

{ 
    "theList": [ 
    { 
     "id": 1, 
     "name": "Horst" 
    }, 
    { 
     "id": 2, 
     "name": "Fritz" 
    }, 
    { 
     "id": 3, 
     "name": "Walter" 
    }, 
    { 
     "id": 4, 
     "name": "Gerhart" 
    }, 
    { 
     "id": 5, 
     "name": "Harmut" 
    } 
    ] 
} 

Tôi muốn lọc danh sách đó để chỉ hiển thị các yếu tố với id có giá trị 2 và 4, do đó, sản lượng dự kiến ​​là:

{ 
    "id": 2, 
    "name": "Fritz" 
}, 
{ 
    "id": 4, 
    "name": "Gerhart" 
} 

Làm cách nào để lọc json bằng jq? Tôi đã chơi xung quanh với các phím chọn và bản đồ, nhưng không có bất kỳ của những để làm việc, ví dụ:

$ jq '.theList[] | select(.id == 2) or select(.id == 4)' array.json 
true 
+2

** Mọi người vui lòng lưu ý: ** Câu hỏi là về [jq] (http://stedolan.github.io/jq/#), không phải jQuery. –

+0

@ T.J.Crowder YMMD ^^ Và tôi đã làm rõ trong câu hỏi: D – k0pernikus

Trả lời

19

Từ các tài liệu:

jq '.[] | select(.id == "second")' 

Input[{"id": "first", "val": 1}, {"id": "second", "val": 2}]

Đầu ra{"id": "second", "val": 2}

Tôi nghĩ rằng bạn có thể làm một cái gì đó như thế này:

jq '.theList[] | select(.id == 2 or .id == 4)' array.json 
+0

'jq '.theList [] | chọn (.id == 2) hoặc chọn (.id == 4) 'array.json' đưa ra: 'true' o.O – k0pernikus

+2

Nó trả về đánh giá cả hai mệnh đề, hãy thử: ' jq' .theList [] | chọn (.id == 2 hoặc .id == 4) '' –

+0

' jq' .theList [] | chọn (.id == 2 hoặc .id == 4) 'array.json' đã làm thủ thuật, bạn có thể cập nhật câu trả lời của bạn :) – k0pernikus

7

Bạn có thể sử dụng trong vòng selectmap.

.theList | map(select(.id == (2, 4))) 

Hoặc gọn hơn:

[ .theList[] | select(.id == (2, 4)) ] 

Mặc dù được viết theo cách đó là một chút không hiệu quả kể từ khi biểu hiện được nhân đôi cho mỗi giá trị được so sánh. Nó sẽ có hiệu quả hơn và có thể dễ đọc hơn bằng văn bản theo cách này:

[ .theList[] | select(any(2, 4; . == .id)) ] 
+0

Sử dụng thông minh [nếu hành vi khi điều kiện trả về nhiều kết quả] (https: // github. com/stedolan/jq/blob/master/docs/content/3.manual/manual.yml # L2033-L2035)! – jq170727

0

Đây là một giải pháp sử dụng indices:

.theList | [ .[map(.id)|indices(2,4)[]] ] 
2

Sử dụng select(.id == (2, 4)) đây nói chung là không hiệu quả (xem dưới đây).

Nếu JQ của bạn có IN/1, sau đó nó có thể được sử dụng để đạt được một giải pháp hiệu quả hơn:

.theList[] | select(.id | IN(2,3)) 

Nếu JQ của bạn không có IN/1, sau đó bạn có thể định nghĩa nó như sau:

def IN(s): first(select(s == .)) // false; 

Hiệu quả

Một cách để xem tính không hiệu quả là sử dụng debug.Biểu thức sau đây, ví dụ, dẫn đến 10 cuộc gọi đến debug, trong khi chỉ có 9 phiếu cho bình đẳng thực sự cần thiết:

.theList[] | select((.id == (2,3)) | debug) 

["DEBUG:",false] 
["DEBUG:",false] 
["DEBUG:",true] 
{ 
    "id": 2, 
    "name": "Fritz" 
} 
["DEBUG:",false] 
["DEBUG:",false] 
["DEBUG:",true] 
{ 
    "id": 3, 
    "name": "Walter" 
} 
["DEBUG:",false] 
["DEBUG:",false] 
["DEBUG:",false] 
["DEBUG:",false] 

index/1

Về nguyên tắc, sử dụng index/1 nên hiệu quả, nhưng tính đến thời điểm viết bài này (tháng 10 năm 2017), việc thực hiện nó, mặc dù nhanh (được viết bằng C), là không hiệu quả.

Các vấn đề liên quan