Trong bài viết gần đây, Stringee và các bạn đã cùng nhau tìm hiểu về hàm filter và cách sử dụng nó trong MongoDB để tính toán và lọc các dữ liệu. Trong tuần này, chúng ta sẽ cùng nhau tìm hiểu cách truy vấn dữ liệu sử dụng regular expression, từ đó chúng ta có thể truy vấn được các thông tin có chung một đặc điểm mà chúng ta muốn.
1. Regex trong MongoDB
Regex trong MongoDB là một hàm được biểu hiện bởi cú pháp $regex, nó cung cấp khả năng tìm kiếm các chuỗi match với biểu thức chính quy mà chúng ta sử dụng trong truy vấn.
Cú pháp sử dụng:
{ <field>: { $regex: /pattern/, $options: '<options>' } }
{ "<field>": { "$regex": "pattern", "$options": "<options>" } }
{ <field>: { $regex: /pattern/<options> } }
Trong MongoDB bạn có thể sử dụng các đối tượng là biểu thức chính quy ví dụ như /pattern/ để định nghĩa một biểu thức:
{ <field>: /pattern/<options> }
Khi truy vấn, chúng ta có thể sử dụng thêm nhiều tùy chọn tìm kiếm bằng cách truyền nó vào $options, dưới đây là một số tùy chọn có thể được sử dụng ở đây:
Option | Mô tả | Hạn chế trong cú pháp |
i | Cho phép kết quả truy vấn trả về không phụ thuộc vào ký tự viết hoa hay viết thường | |
m | Sử dụng cho các biểu thức có các dấu mỏ neo (^ tại vị trí bắt đầu, $ cho ký tự cuối cùng), match ở đầu hoặc cuối của chuỗi ký tự với nhiều giá trị. Nếu không có tùy chọn này, các dấu mỏ neo sẽ match ở vị trí khởi đầu và kết thúc của chuỗi. | |
x | Mở rộng khả năng để bỏ qua các khoảng trắng trong biểu thức được nạp vào truy vấn $regex nếu không thực hiện escape hoặc include một lớp các ký tự. Ngoài ra, nó có thể bỏ qua các ký tự nằm giữa hoặc bao gồm các ký tự không được escape như # hoặc next line. | Bắt buộc sử dụng $regex với cú pháp có $options |
s | Cho phép các ký tự chấm (.) có thể match toàn bộ các ký tự bao gồm cả ký tự thêm dòng mới. | Bắt buộc sử dụng $regex với cú pháp có $options |
2. Hành vi mà regex thực hiện truy vấn trong MongoDB
2.1. So sánh cú pháp $regex với /pattern/
Để gộp một biểu thức chính quy vào trong một truy vấn $in, chúng ta chỉ có thể sử dụng đối tượng biểu thức chính quy trong Javascript, ví dụ như:
{ name: { $in: [ /^acme/i, /^ack/ ] } }
Bạn không thể sử dụng phương thức $regex trong một phương thức truy vấn $in
Sử dụng truy vấn nội trong một phương thức tìm kiếm sử dụng biểu thức chính quy. Để bao hàm một biểu thức chính quy trong một danh sách các điều kiện truy vấn, ta có thể đặt chúng cách nhau bằng một dấu phẩy (,), sử dụng phương thức $regex, ví dụ:
{ name: { $regex: /acme.*corp/i, $nin: [ 'acmeblahcorp' ] } }
{ name: { $regex: /acme.*corp/, $options: 'i', $nin: [ 'acmeblahcorp' ] } }
{ name: { $regex: 'acme.*corp', $options: 'i', $nin: [ 'acmeblahcorp' ] } }
Để sử dụng một trong hai tùy chọn x và s, bạn phải sử dụng cú pháp $regex với phương thức sử dụng tùy chọn $options. Ví dụ, để sử dụng tùy chọn i và s, bạn phải sử dụng $options cho cả hai:
{ name: { $regex: /acme.*corp/, $options: "si" } }
{ name: { $regex: 'acme.*corp', $options: "si" } }
2.2. PCRE (Perl Compatible Regular Expression) so sánh với JavaScript
Để sử dụng các tính năng hỗ trợ regular expression của PCRE nhưng không hỗ trợ cho JavaScript, chúng ta phải sử dụng phương thức $regex và định nghĩa một biểu thức chính quy dưới dạng một chuỗi.
Để match các chuỗi và bỏ qua viết hoa/thường ta sẽ sử dụng:
- “(?i)” bắt đầu bằng một ký tự không xét viết hoa
- “(?-i)” kết thúc bằng một ký tự không xét viết hoa
Từ phiên bản 6.1, MongoDB sử dụng thư viện PCRE2, bạn có thể tham khảo thêm thông tin về thư viện mới này để cập nhật các biểu thức chính quy mới nhất được áp dụng cho MongoDB.
MongoDB cũng cho phép chúng ta sử dụng $regex và $not.
Toán tử $not có thể thực hiện một biểu thức logic NOT cho các trường hợp sau:
- Đối tượng regular expression (có dạng /pattern/)
db.inventory.find( { item: { $not: /^p.*/ } } )
- Toán tử $regex
db.inventory.find( { item: { $not: { $regex: "^p.*" } } } )
db.inventory.find( { item: { $not: { $regex: /^p.*/ } } } )
2.3. Sử dụng index với $regex
Việc truy vấn có so sánh chữ hoa sẽ trở nên dễ dàng hơn khi sử dụng $regex vì MongoDB sẽ trả về các document match với biểu thức chính quy thay vì phải scan cả index.
Chúng ta hoàn toàn có thể tối ưu MongoDB hơn nữa nếu biểu thức chúng ta sử dụng là một prefix expression, có nghĩa là rất nhiều kết quả có tiềm năng match với truy vấn sẽ sử dụng chung một chuỗi. Điều này cho phép cơ sở dữ liệu có thể tạo một dải dữ liệu từ prefix đó và chỉ trả về các kết quả match trên dải kết quả nó đã lọc ra.
Một prefix expression là một expression khi nó bắt đầu bằng một ký tự ^ hoặc \, tiếp sau sẽ là một chuỗi hoạt nhiều biểu tượng. Ví dụ, biểu thức chính quy /^abc.*/ sẽ được tối ưu chỉ khi các kết quả được trả về trong index bắt đầu bằng abc.
>>> Xem thêm bài viết về MongoDB:
- Tìm hiểu về cơ sở dữ liệu phi quan hệ MongoDB
- Sử dụng map reduce trong MongoDB
- Giới thiệu về GridFS trong MongoDB
3. Cách sử dụng regex trong truy vấn
Chúng ta sẽ thực hiện trên một index có các dữ liệu như sau:
db.products.insertMany( [
{ _id: 100, sku: "abc123", description: "Single line description." },
{ _id: 101, sku: "abc789", description: "First line\nSecond line" },
{ _id: 102, sku: "xyz456", description: "Many spaces before line" },
{ _id: 103, sku: "xyz789", description: "Multiple\nline description" },
{ _id: 104, sku: "Abc789", description: "SKU starts with A" }
] )
3.1. Truy vấn LIKE
db.products.find( { sku: { $regex: /789$/ } } )
Kết quả là:
[
{ _id: 101, sku: 'abc789', description: 'First line\nSecond line' },
{ _id: 103, sku: 'xyz789', description: 'Multiple\nline description' },
{ _id: 104, sku: 'Abc789', description: 'SKU starts with A' }
]
3.2. Truy vấn không xét ký tự viết hoa/thường
db.products.find( { sku: { $regex: /^ABC/i } } )
Kết quả là:
[
{ _id: 100, sku: 'abc123', description: 'Single line description.' },
{ _id: 101, sku: 'abc789', description: 'First line\nSecond line' },
{ _id: 104, sku: 'Abc789', description: 'SKU starts with A' }
]
3.3. Truy vấn match nhiều dòng bắt đầu bằng một dạng biểu thức
db.products.find( { description: { $regex: /^S/, $options: 'm' } } )
Kết quả là:
[
{ _id: 100, sku: 'abc123', description: 'Single line description.' },
{ _id: 101, sku: 'abc789', description: 'First line\nSecond line' },
{ _id: 104, sku: 'Abc789', description: 'SKU starts with A' }
]
Nếu không sử dụng $option ta sẽ thu được:
[
{ _id: 100, sku: 'abc123', description: 'Single line description.' },
{ _id: 104, sku: 'Abc789', description: 'SKU starts with A' }
]
3.4. Sử dụng dấu . để match ký tự xuống dòng
db.products.find( { description: { $regex: /m.*line/, $options: 'si' } } )
Kết quả là:
[
{ _id: 102, sku: 'xyz456', description: 'Many spaces before line' },
{ _id: 103, sku: 'xyz789', description: 'Multiple\nline description' }
]
Kết
Trên đây là những chia sẻ từ Stringee về regular expression trong MongoDB, thay vì phải sử dụng các dòng lệnh để lập trình và xử lý kết quả từ các collection như chúng ta thường làm thì việc sử dụng $regex trong MongoDB sẽ là điều đơn giản và hiệu quả hơn rất nhiều.
Stringee Communication APIs là giải pháp cung cấp các tính năng giao tiếp như gọi thoại, gọi video, tin nhắn chat, SMS hay tổng đài CSKH cho phép tích hợp trực tiếp vào ứng dụng/website của doanh nghiệp nhanh chóng. Nhờ đó giúp tiết kiệm đến 80% thời gian và chi phí cho doanh nghiệp bởi thông thường nếu tự phát triển các tính năng này có thể mất từ 1 - 3 năm.
Bộ API giao tiếp của Stringee hiện đang được tin dùng bởi các doanh nghiệp ở mọi quy mô, lĩnh vực ngành nghề như TPBank, VOVBacsi24, VNDirect, Shinhan Finance, Ahamove, Logivan, Homedy, Adavigo, bTaskee…
Quý bạn đọc quan tâm xin mời đăng ký NHẬN TƯ VẤN TẠI ĐÂY: