2014-09-03 19 views
6

Tôi có một tập tin với dòng như thế này:Làm thế nào để chọn các mục trong JQ dựa trên giá trị trong mảng

{"items":["blue","green"]} 
{"items":["yellow","green"]} 
{"items":["blue","pink"]} 

Làm thế nào tôi có thể sử dụng jq để chọn và chỉ hiển thị các giá trị JSON có "màu xanh" trong họ mảng "mục"?

Vì vậy, đầu ra sẽ là:

{"items":["blue","green"]} 
{"items":["blue","pink"]} 
+0

@Tomalak, xin lỗi. "Dòng json" là những gì tôi nên viết. – K2xL

+0

@Tomalak, bạn đang yêu cầu mã nào? Không có mã. – K2xL

+0

Vâng, quên nó đi. Tôi đã lầm. Tôi sẽ xóa các bình luận. – Tomalak

Trả lời

4

Trong khi những gì bạn đã chắc chắn hoạt động, nó sẽ là đúng hơn để sử dụng contains. Tôi sẽ tránh việc sử dụng đó vì nó có thể dẫn đến sự nhầm lẫn. index("blue")0 và người ta sẽ không coi đó là giá trị trung thực và có thể mong đợi nó bị loại trừ khỏi kết quả.

Xem xét sử dụng bộ lọc này để thay thế:

select(.items | contains(["blue"])) 

này có thêm lợi ích mà nó sẽ có tác dụng nếu bạn muốn mục có nhiều hơn một trận đấu bằng cách đơn giản bổ sung thêm vào mảng.

Như sẽ chỉ ra trong nhận xét, điều này không hoàn toàn chính xác. Các chuỗi được so sánh bằng cách sử dụng kết hợp chuỗi con (contains được sử dụng đệ quy) tại đây.

Nhìn lại, contains không hoạt động như tôi nghĩ. Sử dụng index hoạt động, nhưng cá nhân tôi sẽ không sử dụng nó. Có điều gì đó về việc tìm hiểu xem một mục có trong bộ sưu tập hay không bằng cách tìm chỉ mục của nó có cảm giác sai với tôi. Sử dụng contains có ý nghĩa hơn với tôi, nhưng theo thông tin này, nó sẽ không lý tưởng trong trường hợp này.


Dưới đây là một sự thay thế mà nên làm việc một cách chính xác:

select([.items[] == "blue"] | any) 

Hoặc một cách mở rộng hơn nếu bạn muốn để có thể phù hợp với nhiều giá trị:

select(.items as $values | ["blue", "yellow"] | map([$values[] == .] | any) | all) 
+0

Câu trả lời này không đúng. Mặc dù nó sẽ (nguy hiểm) xuất hiện để làm việc trong một số trường hợp, nó cũng có thể dẫn đến dương tính giả. "contains" hoàn toàn là tìm kiếm chuỗi con. Ví dụ truy cập: jq -n '["foobar", "bar", "baz"] | chứa (["foo"]) 'Kết quả là đúng. So sánh với: jq -n '["foobar", "bar", "baz"] | (index ("foo") == null | not) 'kết quả chính xác là sai. –

+0

Cảm ơn bạn đã chỉ ra rằng Will, tôi đã không nhận ra nó chạy bộ lọc đệ quy cho mảng. Tôi chắc chắn có một cách để làm điều này là dự định trong khi vẫn đang được mở rộng. –

+0

Tôi không biết liệu điều này có thể mở rộng hay không, vì tôi nghi ngờ tìm kiếm lặp lại được thực hiện trong mọi trường hợp, nhưng trước đây tôi cũng đã sử dụng: 'jq -n '[" foobar "," bar "," baz " ] | [. [] | chọn (. == "foobar")] | length> 0'' ít nhất có * tiềm năng * để chạy tìm kiếm song song. –

3

Tìm thấy ra câu trả lời

jq 'select(.items | index("blue"))' 
0

On Jan 30, Năm 2017, một tên dựng sẵn có tên là IN đã được thêm vào để kiểm tra hiệu quả liệu một thực thể JSON có được chứa trong luồng hay không. Nó cũng có thể được sử dụng để kiểm tra hiệu quả thành viên trong một mảng. Trong trường hợp hiện tại, việc sử dụng có liên quan sẽ là:

select(.items as $items | "blue" | IN($items[])) 

Nếu JQ của bạn không có IN/1, sau đó chừng nào JQ của bạn có first/1, bạn có thể sử dụng định nghĩa tương đương này:

def IN(s): . as $in | first(if (s == $in) then true else empty end) // false; 

(Trong thực tế, index/1 thường đủ nhanh, nhưng việc triển khai hiện tại (jq 1.5 và phiên bản qua ít nhất là tháng 7 năm 2017) là tối ưu.)

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