Nếu bạn mới bắt đầu thử nghiệm với MongoDB, có lẽ bạn đã đến lúc tài liệu của mình trông hơi phức tạp. Những tài liệu này có thể đã chuyển từ dữ liệu phẳng, trông giống quan hệ sang thứ gì đó có đối tượng lồng nhau, mảng lồng nhau, và thậm chí bốn hoặc năm cấp độ lồng nhau nữa. Vậy làm sao để truy vấn dữ liệu này khi nó nằm sâu vài lớp?
Trong hướng dẫn ngắn này, chúng ta sẽ xem ký hiệu dấu chấm trong MongoDB và xem cách chúng ta có thể nhanh chóng, dễ dàng lọc tài liệu dựa trên dữ liệu chứa các giá trị nhất định trong những trường lồng nhau.
Khi nói đến ký hiệu dấu chấm, chúng ta đang nói về việc phân tách các trường lồng nhau bằng ký tự dấu chấm. Ví dụ:
root_field.nested_field_1.next_layer_nested_field_1Được hỗ trợ bởi
Với mỗi lớp lồng nhau, chúng ta chỉ cần thêm một dấu chấm để phân tách lớp đó khi truy vấn. Chúng ta sẽ xem các ví dụ chi tiết hơn khi đi tiếp trong hướng dẫn.
Để theo học hướng dẫn này thành công, bạn cần triển khai và cấu hình một phiên bản MongoDB. Điều này có nghĩa là bạn đã sẵn sàng bắt đầu sử dụng MongoDB. Bạn cũng nên có ít nhất kiến thức cơ bản về truy vấn các bộ sưu tập trong MongoDB. Tài liệu có thể là nơi khởi đầu tốt nếu bạn cần trợ giúp.
Trong ví dụ này, chúng ta sẽ dùng dữ liệu sau trong cơ sở dữ liệu "dbinc" và bộ sưu tập "people":
Dữ liệu trên đại diện cho hai tài liệu khá phức tạp vì có đối tượng và mảng lồng nhau. Một thông tin thú vị: MongoDB hỗ trợ hơn 100 cấp độ lồng nhau trong tài liệu BSON.
Nếu bạn định làm theo, hãy đảm bảo những tài liệu này tồn tại trong phiên bản MongoDB của bạn.
Truy vấn dữ liệu trong MongoDB bằng nhiều cách tiếp cận
Chúng ta sẽ bắt đầu đơn giản và từ từ chuyển sang phần phức tạp hơn. Tin tốt là phức tạp ở đây không nhất thiết đồng nghĩa với khó.
Giả sử chúng ta muốn tìm tất cả những người trong bộ sưu tập đang làm việc cho MongoDB. Ta có thể thực thi truy vấn như sau:
use dbinc;
db.people.find({"employment.employer":"MongoDB"});Được hỗ trợ bởi
Trong ví dụ này, employer tồn tại như một trường lồng trong đối tượng employment. Chúng ta có thể truy vấn trường đó bằng ký hiệu dấu chấm, đơn giản là các trường được phân tách bởi dấu chấm. Điều này không khác gì nếu ta muốn tìm tất cả những người làm việc ở New York. Ta có thể làm như sau:
use dbinc;
db.people.find({"employment.address.state":"New York"});Được hỗ trợ bởi
Trong truy vấn trên, chúng ta đã đi vào ba cấp của tài liệu, và nó hoạt động bình thường.
Bây giờ, hãy xem cách làm việc với mảng đối tượng lồng nhau đó. Có vài cách truy vấn, tùy thuộc vào điều chúng ta muốn làm.
Giả sử chúng ta muốn trả về tất cả những người có liệt kê website "Portfolio". Ta có thể thực thi truy vấn như sau:
use dbinc;
db.people.find({"websites.name":"Portfolio"});Được hỗ trợ bởi
Truy vấn trên sẽ trả về một kết quả vì chỉ một trong các tài liệu có liệt kê "Portfolio". Lưu ý rằng dù chúng ta có một mảng, ký hiệu dấu chấm vẫn hoạt động ở đây. Điều kiện kèm theo là "Portfolio" phải tồn tại đâu đó trong mảng đó ít nhất một lần.
Đây là lúc mọi thứ trở nên thú vị.
Giả sử chúng ta muốn hạn chế thêm các kết quả trả về. Chúng ta sẽ làm điều này bằng cách thêm tiêu chí lọc, nhưng khi làm việc với các đối tượng lồng trong mảng, mọi thứ hơi khác một chút. Xem ví dụ sau:
use dbinc;
db.people.find({"websites.name":"Portfolio","websites.type":"social"});Được hỗ trợ bởi
Trong ví dụ trên, chúng ta nói rằng muốn những kết quả nơi cả "Portfolio" và "social" đều tồn tại trong mảng, nhưng không nhất thiết trong cùng một đối tượng. Chúng ta chỉ nhận về một kết quả vì tài liệu "Tony Kim" có "social", nhưng không có "Portfolio". Nếu cần kết quả mà cả hai trường phải tồn tại trong cùng một đối tượng, chúng ta sẽ không thể dùng ký hiệu dấu chấm cho việc đó.
Dù nằm ngoài phạm vi của hướng dẫn này, việc dùng toán tử $elemMatch như sau sẽ giải quyết được:
use dbinc;
db.people.find({"websites":{"$elemMatch":{"name":"Portfolio","type":"social"}}});Được hỗ trợ bởi
Không có kết quả nào được trả về trong kịch bản trên vì dữ liệu mẫu của chúng ta không có name và type khớp nhau trong cùng một đối tượng.
Nếu bạn đang làm việc với mảng và biết chỉ số phần tử (index) của mảng mà bạn muốn làm việc, bạn vẫn có thể dùng ký hiệu dấu chấm. Ví dụ, xem đoạn sau:
use dbinc;
db.people.find({"websites.0.name":"Portfolio"});Được hỗ trợ bởi
Truy vấn trên sử dụng chỉ số của mảng mà bạn muốn so khớp. Trong trường hợp này, chúng ta muốn trả về tất cả các tài liệu mà phần tử đầu tiên trong mảng có name là "Portfolio".
Dù nằm ngoài phạm vi của hướng dẫn này, cần lưu ý rằng ký hiệu dấu chấm không chỉ bị giới hạn ở truy vấn chỉ đọc. Bạn có thể dùng ký hiệu dấu chấm như ở đây trong các thao tác cập nhật, chiếu (projection), và pipeline tổng hợp.
Kết luận
Bạn vừa có phần giới thiệu nhanh về việc sử dụng ký hiệu dấu chấm trong các truy vấn MongoDB. Chúng ta đã học:
Ký hiệu dấu chấm hoạt động với các đối tượng lồng nhau.
Bạn có thể dùng ký hiệu dấu chấm cho mảng, nhưng có giới hạn tùy theo kỳ vọng của bạn đối với mảng đó.
Cần dùng toán tử $elemMatch nếu bạn muốn khớp nhiều trường trong cùng một đối tượng của mảng.
Có thể dùng chỉ số mảng trong ký hiệu dấu chấm nếu bạn muốn truy vấn các phần tử nhất định trong mảng.
Dữ liệu trong các bộ sưu tập MongoDB của bạn có thể sẽ không phẳng, nghĩa là đến một lúc nào đó, bạn sẽ có đối tượng lồng nhau, mảng lồng nhau, mảng lồng trong đối tượng, và mọi tổ hợp phức tạp khác. Tin tốt là MongoDB giúp làm việc với thông tin này trở nên dễ dàng nhờ API truy vấn phong phú.
Ký hiệu dấu chấm là cách truy cập các trường lồng nhau trong tài liệu MongoDB thông qua dấu phân tách là dấu chấm.
Tôi có thể lọc với nhiều trường lồng nhau trong truy vấn không?⌄
Có, truy vấn khớp của bạn có thể dùng ký hiệu dấu chấm cho tất cả, một phần, hoặc không cho trường nào cả. Bộ lọc vẫn như nhau—bạn chỉ đang truy cập các mục lồng nhau.
Tôi phải làm gì với các mảng khó đoán?⌄
Bạn nên đảm bảo mảng của mình không vô hạn về kích thước vì lý do dung lượng và hiệu năng, nhưng truy vấn chúng bằng ký hiệu dấu chấm vẫn hoạt động tốt và dễ dàng.
Nếu tôi cần cập nhật tài liệu có đối tượng và mảng lồng nhau thì sao?⌄
Khi dùng thao tác cập nhật, ký hiệu dấu chấm hoạt động cả ở phần bộ lọc lẫn phần thay đổi của thao tác.
Nếu bạn mới bắt đầu thử nghiệm với MongoDB, có lẽ bạn đã đến lúc tài liệu của mình trông hơi phức tạp. Những tài liệu này có thể đã chuyển từ dữ liệu phẳng, trông giống quan hệ sang thứ gì đó có đối tượng lồng nhau, mảng lồng nhau, và thậm chí bốn hoặc năm cấp độ lồng nhau nữa. Vậy làm sao để truy vấn dữ liệu này khi nó nằm sâu vài lớp?
Trong hướng dẫn ngắn này, chúng ta sẽ xem ký hiệu dấu chấm trong MongoDB và xem cách chúng ta có thể nhanh chóng, dễ dàng lọc tài liệu dựa trên dữ liệu chứa các giá trị nhất định trong những trường lồng nhau.
Khi nói đến ký hiệu dấu chấm, chúng ta đang nói về việc phân tách các trường lồng nhau bằng ký tự dấu chấm. Ví dụ:
Với mỗi lớp lồng nhau, chúng ta chỉ cần thêm một dấu chấm để phân tách lớp đó khi truy vấn. Chúng ta sẽ xem các ví dụ chi tiết hơn khi đi tiếp trong hướng dẫn.
Nếu bạn mới bắt đầu với MongoDB, hãy xem khóa học Giới thiệu về MongoDB trong Python của DataCamp.
Điều kiện tiên quyết
Để theo học hướng dẫn này thành công, bạn cần triển khai và cấu hình một phiên bản MongoDB. Điều này có nghĩa là bạn đã sẵn sàng bắt đầu sử dụng MongoDB. Bạn cũng nên có ít nhất kiến thức cơ bản về truy vấn các bộ sưu tập trong MongoDB. Tài liệu có thể là nơi khởi đầu tốt nếu bạn cần trợ giúp.
Trong ví dụ này, chúng ta sẽ dùng dữ liệu sau trong cơ sở dữ liệu "dbinc" và bộ sưu tập "people":
Dữ liệu trên đại diện cho hai tài liệu khá phức tạp vì có đối tượng và mảng lồng nhau. Một thông tin thú vị: MongoDB hỗ trợ hơn 100 cấp độ lồng nhau trong tài liệu BSON.
Nếu bạn định làm theo, hãy đảm bảo những tài liệu này tồn tại trong phiên bản MongoDB của bạn.
Truy vấn dữ liệu trong MongoDB bằng nhiều cách tiếp cận
Chúng ta sẽ bắt đầu đơn giản và từ từ chuyển sang phần phức tạp hơn. Tin tốt là phức tạp ở đây không nhất thiết đồng nghĩa với khó.
Giả sử chúng ta muốn tìm tất cả những người trong bộ sưu tập đang làm việc cho MongoDB. Ta có thể thực thi truy vấn như sau:
Trong ví dụ này,
employertồn tại như một trường lồng trong đối tượngemployment. Chúng ta có thể truy vấn trường đó bằng ký hiệu dấu chấm, đơn giản là các trường được phân tách bởi dấu chấm. Điều này không khác gì nếu ta muốn tìm tất cả những người làm việc ở New York. Ta có thể làm như sau:Trong truy vấn trên, chúng ta đã đi vào ba cấp của tài liệu, và nó hoạt động bình thường.
Bây giờ, hãy xem cách làm việc với mảng đối tượng lồng nhau đó. Có vài cách truy vấn, tùy thuộc vào điều chúng ta muốn làm.
Giả sử chúng ta muốn trả về tất cả những người có liệt kê website "Portfolio". Ta có thể thực thi truy vấn như sau:
Truy vấn trên sẽ trả về một kết quả vì chỉ một trong các tài liệu có liệt kê "Portfolio". Lưu ý rằng dù chúng ta có một mảng, ký hiệu dấu chấm vẫn hoạt động ở đây. Điều kiện kèm theo là "Portfolio" phải tồn tại đâu đó trong mảng đó ít nhất một lần.
Đây là lúc mọi thứ trở nên thú vị.
Giả sử chúng ta muốn hạn chế thêm các kết quả trả về. Chúng ta sẽ làm điều này bằng cách thêm tiêu chí lọc, nhưng khi làm việc với các đối tượng lồng trong mảng, mọi thứ hơi khác một chút. Xem ví dụ sau:
Trong ví dụ trên, chúng ta nói rằng muốn những kết quả nơi cả "Portfolio" và "social" đều tồn tại trong mảng, nhưng không nhất thiết trong cùng một đối tượng. Chúng ta chỉ nhận về một kết quả vì tài liệu "Tony Kim" có "social", nhưng không có "Portfolio". Nếu cần kết quả mà cả hai trường phải tồn tại trong cùng một đối tượng, chúng ta sẽ không thể dùng ký hiệu dấu chấm cho việc đó.
Dù nằm ngoài phạm vi của hướng dẫn này, việc dùng toán tử
$elemMatchnhư sau sẽ giải quyết được:Không có kết quả nào được trả về trong kịch bản trên vì dữ liệu mẫu của chúng ta không có
namevàtypekhớp nhau trong cùng một đối tượng.Nếu bạn đang làm việc với mảng và biết chỉ số phần tử (index) của mảng mà bạn muốn làm việc, bạn vẫn có thể dùng ký hiệu dấu chấm. Ví dụ, xem đoạn sau:
Truy vấn trên sử dụng chỉ số của mảng mà bạn muốn so khớp. Trong trường hợp này, chúng ta muốn trả về tất cả các tài liệu mà phần tử đầu tiên trong mảng có
namelà "Portfolio".Dù nằm ngoài phạm vi của hướng dẫn này, cần lưu ý rằng ký hiệu dấu chấm không chỉ bị giới hạn ở truy vấn chỉ đọc. Bạn có thể dùng ký hiệu dấu chấm như ở đây trong các thao tác cập nhật, chiếu (projection), và pipeline tổng hợp.
Kết luận
Bạn vừa có phần giới thiệu nhanh về việc sử dụng ký hiệu dấu chấm trong các truy vấn MongoDB. Chúng ta đã học:
$elemMatchnếu bạn muốn khớp nhiều trường trong cùng một đối tượng của mảng.Dữ liệu trong các bộ sưu tập MongoDB của bạn có thể sẽ không phẳng, nghĩa là đến một lúc nào đó, bạn sẽ có đối tượng lồng nhau, mảng lồng nhau, mảng lồng trong đối tượng, và mọi tổ hợp phức tạp khác. Tin tốt là MongoDB giúp làm việc với thông tin này trở nên dễ dàng nhờ API truy vấn phong phú.
Nếu bạn chưa sử dụng MongoDB, hãy xem MongoDB Atlas hoặc hướng dẫn khác của tôi minh họa bắt đầu với MongoDB và Docker. Bạn cũng có thể tìm hiểu về Chứng chỉ MongoDB trong hướng dẫn riêng của chúng tôi.