Mở đầu — vì sao bài này quan trọng
Hãy tưởng tượng bạn là Product Manager tại một công ty fintech ở TP.HCM. 9 giờ sáng thứ Hai, sếp nhắn Slack: "Cho anh danh sách tất cả bug ở mức nghiêm trọng còn tồn từ sprint trước, chưa ai nhận, thuộc module thanh toán — trong 10 phút nữa họp." Nếu bạn phải click chuột qua từng filter dropdown trong Jira, lọc thủ công, xuất Excel rồi ngồi highlight, thì 10 phút là không đủ. Nhưng nếu bạn biết JQL, chỉ cần gõ một dòng, nhấn Enter, và có ngay kết quả chính xác.
Đó chính là lý do JQL — Jira Query Language — là kỹ năng phân biệt một PM "biết dùng Jira" với một PM "làm chủ Jira". Ở các bài trước, bạn đã học cách tổ chức Epic, Story, Task (Bài 5), tạo Issue Type (Bài 6) và thiết kế Workflow (Bài 7). Toàn bộ dữ liệu đó nằm trong Jira dưới dạng có cấu trúc. JQL là cách bạn truy vấn kho dữ liệu ấy — giống như SQL truy vấn cơ sở dữ liệu, nhưng đơn giản hơn nhiều và không cần bạn là developer.
Bài này là nền tảng (Foundation) — chúng ta tập trung vào cú pháp cơ bản, các trường (field) quan trọng, toán tử, và cách đọc/viết một câu truy vấn đúng. Bài 9 sẽ đi vào các kỹ thuật JQL nâng cao dành riêng cho PM. Nắm chắc bài này, bạn sẽ tự tin bước vào phần nâng cao mà không bị hụt hơi.
Khái niệm cốt lõi
JQL là gì và không phải là gì
JQL (Jira Query Language) là ngôn ngữ truy vấn dùng để tìm và lọc issue trong Jira dựa trên các điều kiện bạn đặt ra. Điểm quan trọng cần hiểu ngay: JQL không phải là ngôn ngữ lập trình. Bạn không viết vòng lặp, không viết hàm. Bạn chỉ mô tả "tôi muốn tìm những issue thỏa mãn điều kiện gì", và Jira trả về danh sách.
Vì sao PM cần JQL trong khi Jira đã có sẵn bộ lọc bấm chuột (basic filter)?
- Basic filter không đủ linh hoạt. Giao diện bấm chuột chỉ cho phép kết hợp điều kiện theo kiểu "AND" đơn giản. Khi bạn cần logic phức tạp — ví dụ "(A hoặc B) VÀ không phải C" — bạn buộc phải dùng JQL.
- Dashboard và gadget cần JQL. Hầu hết các widget báo cáo trong Jira (bạn sẽ học sâu ở Bài 19) đều lấy dữ liệu đầu vào từ một câu JQL. Không biết JQL thì không tự dựng được dashboard theo ý mình.
- Báo cáo và audit một lần (one-off). Những câu hỏi bất chợt như "tuần này có bao nhiêu ticket bị chuyển trạng thái ngược?" thường không có report dựng sẵn. JQL cho bạn câu trả lời tức thì.
Cấu trúc một câu JQL
Một câu JQL cơ bản gồm ba thành phần:
field operator value
- Field (trường): thuộc tính của issue bạn muốn lọc, ví dụ
project,status,assignee,priority,created. - Operator (toán tử): cách so sánh, ví dụ
=,!=,>,<,IN,~(chứa). - Value (giá trị): giá trị bạn muốn so khớp, ví dụ
"TTT","In Progress",Highest.
project = "PAY"
Câu này trả về tất cả issue thuộc project có mã "PAY".
Các toán tử logic: AND, OR, NOT
Bạn kết hợp nhiều điều kiện bằng toán tử logic:
project = "PAY" AND status = "In Progress"
Trả về issue thuộc project PAY và đang ở trạng thái In Progress.
priority = Highest OR priority = High
Trả về issue có độ ưu tiên Highest hoặc High.
NOT để loại trừ:
project = "PAY" AND NOT status = Done
Một lưu ý cực kỳ quan trọng về thứ tự ưu tiên: giống toán học, AND được xử lý trước OR. Vì vậy câu:
project = "PAY" AND status = "To Do" OR status = "In Progress"
sẽ bị Jira hiểu là (project = "PAY" AND status = "To Do") OR (status = "In Progress") — tức là nó kéo về mọi issue In Progress của mọi project khác, không như bạn mong muốn. Hãy dùng dấu ngoặc để kiểm soát:
project = "PAY" AND (status = "To Do" OR status = "In Progress")
Toán tử IN, NOT IN — gọn hơn nhiều
Thay vì viết status = A OR status = B OR status = C, dùng IN:
status IN ("To Do", "In Progress", "In Review")
Ngược lại, NOT IN loại trừ một nhóm giá trị:
status NOT IN (Done, Closed, Cancelled)
Toán tử ~ (contains) cho trường văn bản
Với các trường dạng text như summary (tiêu đề) hay description, bạn không dùng = mà dùng ~ để tìm chứa từ khóa:
summary ~ "thanh toán"
Trường EMPTY / NULL và trường hệ thống hữu ích
Để tìm issue chưa được gán ai:
assignee IS EMPTY
Một số hàm và giá trị đặc biệt rất đáng nhớ:
currentUser()— chính bạn. Ví dụassignee = currentUser()tìm issue được gán cho bạn.startOfDay(),endOfWeek(),startOfMonth()— mốc thời gian tương đối. Ví dụcreated >= startOfWeek().EMPTY/IS NULL— trường chưa có giá trị.
ORDER BY — sắp xếp kết quả
Cuối câu JQL, bạn có thể thêm sắp xếp:
project = "PAY" AND status != Done ORDER BY priority DESC, created ASC
Kết quả sẽ được sắp theo priority giảm dần, rồi theo ngày tạo tăng dần.
Tình huống thực tế
Tình huống 1 — Momo-style fintech: tìm bug tồn đọng trước cuộc họp
Bối cảnh: Chị Lan là PM module thanh toán tại một ví điện tử lớn ở Việt Nam (project code "PAY"). Team QA vừa dồn về 40 bug sau đợt test release. Sếp muốn biết ngay: những bug nghiêm trọng nhất, chưa ai nhận, chưa đóng thuộc module thanh toán.
Chị Lan gõ:
project = "PAY" AND issuetype = Bug AND priority IN (Highest, High) AND assignee IS EMPTY AND status != Done ORDER BY created DESC
Diễn giải từng phần: chỉ lấy project PAY, chỉ lấy issue là Bug, chỉ lấy độ ưu tiên Highest hoặc High, chưa gán ai (assignee IS EMPTY), chưa xong (status != Done), và sắp xếp bug mới nhất lên đầu. Kết quả: 7 bug hiện ra trong 5 giây.
Bài học rút ra: JQL biến một câu hỏi kinh doanh mơ hồ thành một truy vấn chính xác. Khi bạn tách được câu hỏi thành các điều kiện field–operator–value, việc còn lại chỉ là ráp chúng bằng AND.
Tình huống 2 — Tiki-style e-commerce: audit công việc của cả team trong sprint
Bối cảnh: Anh Minh là PM tại một sàn thương mại điện tử, quản lý team 8 người. Cuối sprint, anh muốn kiểm tra ai còn ticket dang dở để nhắc trong buổi retro (Bài 13). Anh cần các issue thuộc sprint hiện tại, chưa hoàn thành, và gom theo người phụ trách.
project = "SHOP" AND sprint IN openSprints() AND status NOT IN (Done, Closed) ORDER BY assignee ASC, priority DESC
openSprints() là hàm trả về mọi sprint đang mở của board — rất tiện vì anh Minh không phải gõ tay tên sprint mỗi lần. Kết quả được sắp theo tên người rồi theo độ ưu tiên, nên anh nhìn một phát là thấy từng người còn "gánh" bao nhiêu.
Sau buổi retro, anh Minh còn muốn xem riêng phần việc của bạn dev mới vào tên Huy:
project = "SHOP" AND assignee = "huy.tran" AND status = "In Progress"
Bài học rút ra: Các hàm như openSprints() và currentUser() giúp câu truy vấn tự cập nhật theo thời gian — bạn lưu filter một lần, dùng mãi cho các sprint sau mà không cần sửa.
Tình huống 3 — Startup SaaS ở Singapore: đo lượng việc phát sinh trong tuần
Bối cảnh: Sarah, PM của một startup SaaS phục vụ thị trường Đông Nam Á, nghi ngờ team đang bị "nhồi" quá nhiều yêu cầu giữa sprint (scope creep). Cô muốn đếm xem trong tuần này có bao nhiêu issue mới được tạo mà không nằm trong kế hoạch ban đầu (không gán vào sprint nào).
project = "CORE" AND created >= startOfWeek() AND sprint IS EMPTY ORDER BY created DESC
startOfWeek() tự động lấy mốc đầu tuần hiện tại, nên câu này chạy được vào bất kỳ tuần nào. sprint IS EMPTY lọc ra những issue chưa được đưa vào sprint — dấu hiệu của việc phát sinh ngoài kế hoạch. Con số Sarah thu được: 23 issue mới chỉ trong 4 ngày, nhiều gấp đôi tuần trước. Đây là bằng chứng số liệu để cô mang ra thảo luận với stakeholder về việc siết quy trình tiếp nhận yêu cầu.
Bài học rút ra: JQL không chỉ để tìm việc, mà còn để đo xu hướng. Một câu truy vấn đơn giản có thể trở thành công cụ phát hiện vấn đề quy trình.
Hướng dẫn từng bước
Đây là quy trình để bạn viết một câu JQL từ con số 0:
- Diễn đạt câu hỏi bằng tiếng Việt trước. Ví dụ: "Tôi muốn tìm mọi Story thuộc project APP, được gán cho tôi, và chưa hoàn thành." Đừng vội gõ, hãy nói rõ điều kiện trong đầu.
- Tách câu hỏi thành các điều kiện field–operator–value. Từ ví dụ trên:
project = "APP",issuetype = Story,assignee = currentUser(),status != Done.
- Mở khung tìm kiếm nâng cao. Trong Jira, vào Filters → Advanced issue search (hoặc View all issues), rồi chuyển từ chế độ Basic sang JQL (nút "Switch to JQL"). Đây là nơi bạn gõ trực tiếp câu truy vấn.
- Gõ từng điều kiện và tận dụng auto-complete. Jira gợi ý tên field, toán tử và giá trị hợp lệ khi bạn gõ. Hãy dựa vào gợi ý này để tránh gõ sai tên — đây là "bánh xe phụ" tốt nhất cho người mới.
- Nối các điều kiện bằng AND / OR và thêm ngoặc khi cần. Ghép lại thành:
project = "APP" AND issuetype = Story AND assignee = currentUser() AND status != Done
- Thêm ORDER BY để dễ đọc. Ví dụ
ORDER BY updated DESCđể issue mới cập nhật lên đầu.
- Nhấn Enter, kiểm tra kết quả. Nếu Jira báo lỗi đỏ, đọc kỹ thông báo — thường là sai tên field hoặc thiếu dấu ngoặc kép.
- Lưu lại thành filter (Save as). Đặt tên rõ ràng như "My open stories — APP". Filter đã lưu có thể tái sử dụng, chia sẻ cho team, và cắm vào dashboard sau này.
Lỗi thường gặp & mẹo
Lỗi 1 — Nhầm = với ~ cho trường text. Với summary hay description, dùng = sẽ chỉ khớp khi toàn bộ nội dung trùng khít, gần như luôn ra rỗng. Hãy dùng ~ để tìm chứa từ khóa: summary ~ "login".
Lỗi 2 — Quên dấu ngoặc kép cho giá trị có khoảng trắng. status = In Progress sẽ lỗi vì Jira không hiểu "Progress" là gì. Phải viết status = "In Progress". Quy tắc: giá trị có dấu cách hoặc ký tự đặc biệt thì bọc trong ngoặc kép.
Lỗi 3 — Không hiểu thứ tự ưu tiên AND/OR. Như đã phân tích ở trên, AND chạy trước OR. Khi trộn hai loại, luôn dùng ngoặc để làm rõ ý định. Đây là lỗi khiến kết quả "sai mà không báo lỗi" — nguy hiểm nhất vì bạn tưởng đúng.
Lỗi 4 — Dùng status = Open nhưng workflow không có status tên "Open". Tên status, priority, issue type phải khớp chính xác với cấu hình trong project của bạn (nhớ lại Bài 7 về workflow). Hãy để auto-complete gợi ý giá trị đúng thay vì gõ chay theo trí nhớ.
Lỗi 5 — Nhầm giữa EMPTY và giá trị rỗng chuỗi. Để tìm trường chưa có giá trị, dùng field IS EMPTY hoặc field IS NULL, không phải field = "".
Mẹo hữu ích:
- Xây dần từng bước. Viết một điều kiện, chạy thử, thấy đúng rồi mới thêm điều kiện tiếp theo. Debug từng lớp dễ hơn nhiều so với gõ một câu dài rồi loay hoay tìm lỗi.
- Dùng chế độ Basic để "học lỏm" JQL. Lọc bằng giao diện bấm chuột, rồi bấm "Switch to JQL" — Jira sẽ tự dịch ra câu JQL tương ứng. Đây là cách học cú pháp cực nhanh.
- Ưu tiên hàm thời gian tương đối (
startOfWeek(),endOfMonth()) thay vì gõ ngày cứng như"2026/06/01", để filter tự đúng mãi về sau. - Đặt tên filter theo công thức "Đối tượng — Điều kiện — Project" để cả team hiểu ngay filter làm gì.
Bài tập thực hành
Hãy mở Jira (dùng project thật của bạn, hoặc tạo một project sandbox miễn phí trên Atlassian Cloud) và viết các câu JQL sau:
- Tìm tất cả issue được gán cho chính bạn và chưa hoàn thành. (Gợi ý:
currentUser(),status != Done.)
- Tìm tất cả Bug có độ ưu tiên Highest hoặc High trong một project bất kỳ, sắp xếp theo ngày tạo mới nhất. (Gợi ý:
IN,ORDER BY created DESC.)
- Tìm mọi issue được tạo trong tuần này mà chưa được gán cho ai. (Gợi ý:
startOfWeek(),assignee IS EMPTY.)
- Viết một câu JQL trộn AND và OR có dùng ngoặc: tìm issue thuộc project của bạn, đang ở trạng thái "To Do" hoặc "In Progress", và có priority từ High trở lên.
- Tìm mọi issue có tiêu đề chứa từ "payment" hoặc "thanh toán". (Gợi ý: dùng
~.)
- Thử thách: lấy câu số 4, chuyển sang chế độ Basic bằng nút "Switch to Basic" để xem Jira biểu diễn nó ra sao, rồi lưu lại thành filter với tên đặt theo công thức đã học.
Tóm tắt
JQL là ngôn ngữ truy vấn giúp PM tìm, lọc và đo lường dữ liệu issue trong Jira một cách chính xác và nhanh chóng — vượt xa giới hạn của bộ lọc bấm chuột. Ba điểm cốt lõi cần khắc ghi:
- Cấu trúc nền tảng là
field operator value, nối với nhau bằngAND,OR,NOT, và luôn dùng ngoặc khi trộn AND với OR. - Nắm các field và hàm thông dụng —
project,status,assignee,priority,created, cùngcurrentUser(),openSprints(),startOfWeek(),IS EMPTY— là đủ để giải quyết 80% nhu cầu hằng ngày. - Xây dần, thử liên tục, tận dụng auto-complete, và lưu lại các câu truy vấn hữu ích thành filter để tái sử dụng và cắm vào dashboard.