Như chúng ta đã biết, việc sử dụng Aggregation trong mongoDb để thực hiện xử lý dữ liệu trong MongoDb là rất cần thiết. Aggregation is a framework mạnh mẽ linh hoạt trong quá trình truy vấn và xử lý dữ liệu với các toán tử mạnh mẽ cũng như hỗ trợ xử lý dữ liệu với số lượng lớn
Các lưu ý cần thiết
Các công cụ cơ bản
- maven
- khởi động mùa xuân
- cơ sở dữ liệu. MongoDb [có thể tải xuống tại https. //www. mongodb. com/download-center/community lựa chọn hệ điều hành phù hợp và tải xuống]
- phụ thuộc. Spring boot web , Spring boot data mongodb
- Robo3T
- Người phát thơ
Lưu ý
- Trong loạt bài viết này sẽ trình bày xử lý Aggregation trong mùa xuân. Các thao tác xử lý cơ bản như CRUD sẽ không được cập nhật trong bài viết này. Các bạn có thể tìm hiểu thêm trên internet. Về mặt cơ bản các thuật toán CRUD trong mongoDb vẫn xử lý các lý do tương tự như trong hệ thống cơ sở dữ liệu [RDBMS]. Bài viết này sẽ trình bày thêm về việc xử lý dữ liệu dựa trên con trỏ để xử lý các bản ghi vượt quá 16mb
Các thuật ngữ thường dùng trong bài viết
Khác với hệ cơ sở dữ liệu RDBMS, Spring data MongoDb sử dụng thuật ngữ khác để thực hiện ánh xạ, xử lý và thao tác trên MongoDb, Dưới đây là bảng so sánh giữa 2 hệ thống cơ sở dữ liệu và sự khác nhau của nó
MongoDbRDBMSÝ nghĩaDocumentEntityĐánh dấu đây là một lớp có thể thực hiện thao tác ánh xạ và xử lý dữ liệu với cơ sở dữ liệu, xác định tên DocumentFieldColumnXác định tên cột [với RDBMS ] hoặc tên trường với MongoDb để thực hiện ánh xạBài viết sẽ thực hiện bằng cách sử dụng Thao tác tổng hợp với Bộ sưu tập tên DB là Nhân viên bao gồm các thông tin như bên dưới
/* 1 */ { "_id" : ObjectId["5daa7b6cd20119058c403b85"], "firstName" : "A", "lastName" : "Nguyen Van", "age" : 25, "location" : "DN", "salary" : 22.2 } /* 2 */ { "_id" : ObjectId["5daa7b6cd20119058c403b86"], "firstName" : "B", "lastName" : "Tran Van", "age" : 27, "location" : "HN", "salary" : 22.7 } /* 3 */ { "_id" : ObjectId["5daa7b6cd20119058c403b87"], "firstName" : "C", "lastName" : "Le Van", "age" : 28, "location" : "DN", "salary" : 80.2 }
Thực hiện
Trước tiên cần tiến hành tạo dự án bằng spring boot bằng cách truy cập vào trang bắt đầu. mùa xuân. io với cấu hình thông tin như bên dưới. [email protected]:27017/BaoTrung spring.jpa.show-sql=true logging.level.org.springframework.data.mongodb.core.MongoTemplate=DEBUG logging.level.org.springframework.web = DEBUG
Cấu hình trên máy chủ duy nhất đang chạy ở cổng 8989, mùa xuân. dữ liệu. mongodb. uri định cấu hình kết nối với cơ sở dữ liệu với các thông số như tên người dùng là root mật khẩu là root , cổng 27017[default của mongoDb] và cơ sở dữ liệu là BaoTrung.
Các thông số tiếp theo chỉ định việc hiển thị lệnh khi thao tác với mongoDb cũng như nhật ký cấp độ khi thực hiện thao tác. Trong loạt bài viết đang sử dụng ở mức gỡ lỗi.
Có một lưu ý ở đây. Trong bài viết đang sử dụng Mongo 3. 0 Trình điều khiển Java ,cấu hình sẽ thông qua uri. Cấu hình bên dưới sẽ không thành công đối với phiên bản Mongo 3. 0 Trình điều khiển Java trở lên [chỉ áp dụng với Mongo 3. 0 Java driver trở xuống]. Lý do là mùa xuân. dữ liệu. mongodb. máy chủ và mùa xuân. dữ liệu. mongodb. cổng đã bị loại bỏ trong Mongo 3. 0 Trình điều khiển Java
//Không áp dụng được với Mongo 3. 0 Trình điều khiển Java trở lên
spring.data.mongodb.authentication-database=admin spring.data.mongodb.username=root spring.data.mongodb.password=root spring.data.mongodb.database=baotrung spring.data.mongodb.port=27017 spring.data.mongodb.host=localhost
Kiểu mẫu
Thực hiện tạo một lớp có tên là Employee phía dưới
Người lao động. lớp
@Document[collection = "Employees"] public class Employee { @Id private String id; @Field[value = "firstName"] @NotBlank[message = "FirstName can't empty!"] private String firstName; @NotBlank[message = "LastName can't empty!"] private String lastName; @NotNull private Integer age; @NotBlank[message = "Location can't empty!"] private String location; private Double salary; public Employee[] { } public Employee[String id, String firstName, String lastName, Integer age, String location, Double salary] { this.id = id; this.firstName = firstName; this.lastName = lastName; this.age = age; this.location = location; this.salary = salary; } public String getId[] { return id; } public void setId[String id] { this.id = id; } public String getFirstName[] { return firstName; } public void setFirstName[String firstName] { this.firstName = firstName; } public String getLastName[] { return lastName; } public void setLastName[String lastName] { this.lastName = lastName; } public Integer getAge[] { return age; } public void setAge[Integer age] { this.age = age; } public String getLocation[] { return location; } public void setLocation[String location] { this.location = location; } public Double getSalary[] { return salary; } public void setSalary[Double salary] { this.salary = salary; } @Override public String toString[] { return "Employee{" + "id='" + id + '\'' + ", firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + ", age=" + age + ", location='" + location + '\'' + ", salary=" + salary + '}'; } }
Lớp trên đơn giản chỉ được sử dụng @Document xác định nó là một thực thể để có thể thao tác với MongoDb với các trường như FirstName, LastName, Salary ,Age, Location. Có một lưu ý ở đây là do ở MongoDb đang sử dụng tên tài liệu là Nhân viên nên nếu muốn ánh xạ đúng tên tài liệu tên là Nhân viên thì chúng ta sẽ sử dụng
spring.data.mongodb.authentication-database=admin spring.data.mongodb.username=root spring.data.mongodb.password=root spring.data.mongodb.database=baotrung spring.data.mongodb.port=27017 spring.data.mongodb.host=localhost1
Tạo một tên lớp là EmployeeController và xác định các api cần thiết cho việc xử lý dữ liệu. Ở đây chúng ta sẽ xác định các api như findByLocation , computeTotalUser và calculatorSalary
Bộ điều khiển
nhân viênđiều khiển
@RestController @RequestMapping[value = "/employees", produces = MediaType.APPLICATION_JSON_VALUE] public class EmployeeController { @Autowired private EmployeeRepository employeeRepository; @GetMapping["/findByLocation"] public ResponseEntity fetchAllLastNameByLocation[@RequestParam String location] { return ResponseEntity.ok[employeeRepository.fetchAllLastNameByLocation[location]]; } @GetMapping["/calculateTotalUser"] public ResponseEntity countTotalEmployeeByLocation[@RequestParam String location] { return ResponseEntity.ok[employeeRepository.countTotalUserByLocation[location]]; } @GetMapping["/calculateSalary"] public ResponseEntity calculateSalaryByAgeAndLocation[@RequestParam int age, @RequestParam String location] { return ResponseEntity.ok[employeeRepository.calculateSalaryByAgeAndLocation[age, location]]; } }
Lớp điều khiển phía trên sẽ xác định các api cần thiết, các tham số đầu vào và trả về phản hồi chứa dữ liệu được bao bọc trong các DTO như EmployeeResult ,EmployeeDto dựa trên thông tin của mỗi API. Các DTO này sẽ được định nghĩa bên dưới. Lưu ý rằng ở đây bộ điều khiển sẽ gọi trực tiếp đến kho lưu trữ không thông qua lớp dịch vụ hiện tại không có nhiều logic phức tạp để xử lý và đây là các trình xử lý đơn giản. Tùy theo logic và các yêu cầu mà các bạn có thể sử dụng để phù hợp trong từng dự án
Tạo giao diện với tên là EmployeeRepository và EmployeeRepositoryCustom
Kho lưu trữ nhân viên
public interface EmployeeRepository extends CrudRepository, EmployeeRepositoryCustom { }
Nhân viênKho lưu trữ Tùy chỉnh
public interface EmployeeRepositoryCustom { List fetchAllLastNameByLocation[String location]; List countTotalUserByLocation[String location]; List calculateSalaryByAgeAndLocation[int age,String location]; }
Ở giao diện EmployeeRepositoryCustom chúng ta sẽ định cấu hình 3 method là
- fetchAllLastNameByLocation với tham số là vị trí và trả về 1 danh sách LastName dựa trên vị trí,
- countTotalUserByLocation với tham số là vị trí và trả về 1 danh sách tổng số người dùng theo vị trí dựa trên DTO EmployeeResult
- TínhSalaryByAgeAndLocation với tham số là vị trí và trả về 1 danh sách các mức lương tương ứng dựa trên tuổi và vị trí
nhân viênkết quả
________số 8nhân viênDto
package com.baotrung.springbootdemomongodb.dto; public class EmployeeDto { private String _id; private Long totalSalary; private String lastName; public EmployeeDto[] { } public String get_id[] { return _id; } public void set_id[String _id] { this._id = _id; } public Long getTotalSalary[] { return totalSalary; } public void setTotalSalary[Long totalSalary] { this.totalSalary = totalSalary; } public String getLastName[] { return lastName; } public void setLastName[String lastName] { this.lastName = lastName; } }
Tạo một lớp có tên là EmployeeRepositoryCustomImpl và thực hiện triển khai lại EmployeeRepositoryCustom như phía bên dưới
server.port=8989 spring.data.mongodb.uri=mongodb://root:[email protected]:27017/BaoTrung spring.jpa.show-sql=true logging.level.org.springframework.data.mongodb.core.MongoTemplate=DEBUG logging.level.org.springframework.web = DEBUG0
Chúng ta sẽ thực hiện tính toán trong 3 phương thức này bằng cách sử dụng Aggregation dựa vào MongoTemplate. Vậy MongoTemplate là gì ?
Lớp MongoTemplate, nằm trong gói org. khung mùa xuân. dữ liệu. tài liệu. mongodb, cung cấp các tính năng phong phú được thiết lập để tương tác với cơ sở dữ liệu. MongoTemplate cung cấp các phương pháp được sử dụng để tạo, cập nhật, xóa và truy vấn tài liệu MongoDB và cung cấp ánh xạ giữa các mô hình và tài liệu. Đây là một lớp rất quan trọng trong thao tác với mongoDb
Tích hợp MongoTemplate vào EmployeeRepositoryCustom như sau
server.port=8989 spring.data.mongodb.uri=mongodb://root:[email protected]:27017/BaoTrung spring.jpa.show-sql=true logging.level.org.springframework.data.mongodb.core.MongoTemplate=DEBUG logging.level.org.springframework.web = DEBUG0
Đối với phương thức fetchAllLastNameByLocation sẽ tiến hành xử lý như sau
server.port=8989 spring.data.mongodb.uri=mongodb://root:[email protected]:27017/BaoTrung spring.jpa.show-sql=true logging.level.org.springframework.data.mongodb.core.MongoTemplate=DEBUG logging.level.org.springframework.web = DEBUG1
Ở đây chúng ta có một lớp gọi là Tiêu chí. Vậy Tiêu chí là gì ? . khung mùa xuân. dữ liệu. mongodb. cốt lõi. truy vấn cung cấp nhiều phương thức để thực hiện truy vấn như WHERE , IS , LT, GT … Nó cũng cung cấp một cách tuần tự việc thực hiện các truy vấn đó
spring.data.mongodb.authentication-database=admin spring.data.mongodb.username=root spring.data.mongodb.password=root spring.data.mongodb.database=baotrung spring.data.mongodb.port=27017 spring.data.mongodb.host=localhost2 dùng để tạo ra một tiêu chí chứa điều kiện là các vị trí trong cơ sở dữ liệu phải bằng với vị trí từ tham số đã nhập vào từ Bộ điều khiển
server.port=8989 spring.data.mongodb.uri=mongodb://root:[email protected]:27017/BaoTrung spring.jpa.show-sql=true logging.level.org.springframework.data.mongodb.core.MongoTemplate=DEBUG logging.level.org.springframework.web = DEBUG2
Câu lệnh trên được sử dụng để thực hiện tạo một đường ống có khớp toán tử [tiêu chí] với tiêu chí đã định nghĩa về phía trên và nhóm theo tên cuối cùng
Kế đến câu lệnh.
______23
sử dụng mongoTemplate thao tác với cơ sở dữ liệu với aggregation đã định nghĩa phía trên, tên bộ sưu tập là Nhân viên và trả về DTO là EmployeeDto. lớp
Cuối cùng các câu lệnh như phía dưới thực hiện tạo ra 1 danh sách các LastName với kiểu String, lấy kết quả từ các kết quả đã trả về , lặp và trả về danh sách các LastName
Kết quả khi thực hiện cuộc gọi API trên người đưa thư
Nhìn vào log trong spring, chúng ta có thể thấy dễ dàng Spring Data Mongo đã thực hiện phân tích cú pháp lệnh chúng ta viết phía sau cú pháp MongoDb theo dạng Pipeline tuần tự. khớp -> nhóm và thực hiện thao tác với MongoDb
server.port=8989 spring.data.mongodb.uri=mongodb://root:[email protected]:27017/BaoTrung spring.jpa.show-sql=true logging.level.org.springframework.data.mongodb.core.MongoTemplate=DEBUG logging.level.org.springframework.web = DEBUG3
Đối với phương thức countTotalUserByLocation sẽ thực hiện tính toán như sau
server.port=8989 spring.data.mongodb.uri=mongodb://root:[email protected]:27017/BaoTrung spring.jpa.show-sql=true logging.level.org.springframework.data.mongodb.core.MongoTemplate=DEBUG logging.level.org.springframework.web = DEBUG4
Cách thực hiện tương tự như ví dụ trên. Thực hiện việc tạo dựa trên một Tiêu chí để thực hiện tìm kiếm dựa trên Vị trí và sử dụng Aggregation để tạo các Pipeline để thực hiện theo tuần tự. Nhóm vị trí và thực hiện Đếm trên từng vị trí đó. Tuy nhiên, có 1 sự khác biệt là chúng ta sẽ sử dụng thêm một lớp là AggregationOperation để xử lý riêng cho từng toán tử như đối sánh , nhóm … Điều này làm cho mã của chúng ta rõ ràng và dễ dàng duy trì hơn. Ở đây chúng ta sẽ thực hiện lấy kết quả trực tiếp từ AggregationResults bằng phương thức getMappedResults được định nghĩa sẵn trong api của mongoDb
Kết quả khi thực hiện api. Kết quả hiển thị trên log spring.
server.port=8989 spring.data.mongodb.uri=mongodb://root:[email protected]:27017/BaoTrung spring.jpa.show-sql=true logging.level.org.springframework.data.mongodb.core.MongoTemplate=DEBUG logging.level.org.springframework.web = DEBUG5
Cũng tương tự như ví dụ về phía trên, Spring Data MongoDb dựa trên các lệnh chúng tôi đã viết để thực hiện việc tạo các Đường ống theo tuần tự. $match theo vị trí , $group theo vị trí và tính tổng dựa trên $sum
Đối với phương thức calculateSalaryByAgeAndLocation thực hiện xử lý như sau
server.port=8989 spring.data.mongodb.uri=mongodb://root:[email protected]:27017/BaoTrung spring.jpa.show-sql=true logging.level.org.springframework.data.mongodb.core.MongoTemplate=DEBUG logging.level.org.springframework.web = DEBUG6
Đối với phương thức calculateSalaryByAgeAndLocation sẽ thực hiện tính toán dựa trên 2 đk. tuổi và địa điểm. Tiêu chí sẽ thực hiện lấy những đk có tuổi lớn hơn hoặc bằng tuổi được nhập vào và vị trí bằng vị trí từ tham số được nhập vào. Toán tử AggregationOperation sẽ thực hiện tương tự các trình tự như đối sánh, nhóm theo vị trí, tổng dựa trên tiền lương và thực hiện tham chiếu đến từng Họ của Nhân viên bằng lệnh đẩy
Kết quả
Nhật ký
server.port=8989 spring.data.mongodb.uri=mongodb://root:[email protected]:27017/BaoTrung spring.jpa.show-sql=true logging.level.org.springframework.data.mongodb.core.MongoTemplate=DEBUG logging.level.org.springframework.web = DEBUG7
We can see. Spring Mongo Db đã phân tích cú pháp các câu lệnh mà chúng viết ra dưới dạng Pipeline , với các toán tử khớp. tuổi lớn hơn hoặc bằng 23, vị trí Nhóm DN theo vị trí tính tổng lương …
Thao tác MongoDb dựa trên Tập hợp với Con trỏ
Qua các ví dụ trên mongoTemplate cung cấp rất nhiều tiện ích cũng như phương thức thao tác với mongoDb. Tuy nhiên có 1 hạn chế ở đây ? . Vì sao như vậy?
Về con trỏ là gì cũng như có những phương thức nào các bạn có thể tham khảo tài liệu của MongoDb. https. // tài liệu. mongodb. com/manual/reference/method/js-cursor/?searchProperty=current&query=Cursor. Lưu ý là Cursor có các phương thức riêng để xử lý, không thể sử dụng các phương thức của bộ sưu tập để xử lý Cursor
Lưu ý. Lí do sử dụng dựa trên Con trỏ chỉ áp dụng đối với lượng dữ liệu vượt quá 16 MB. Nếu dữ liệu nhỏ hơn 16 MB, hãy sử dụng mongoTemplate. Con trỏ sử dụng sẽ khiến cơ sở dữ liệu của bạn chậm đi đáng kể dẫn đến hiệu suất không ổn định
Thao tác con trỏ trong Spring
Trước tiên chúng ta tạo 1 phương thức trong lớp EmployeeController như thế này
server.port=8989 spring.data.mongodb.uri=mongodb://root:[email protected]:27017/BaoTrung spring.jpa.show-sql=true logging.level.org.springframework.data.mongodb.core.MongoTemplate=DEBUG logging.level.org.springframework.web = DEBUG8
Phương thức này sẽ trả về 1 danh sách các LastName không trùng lặp
Tiếp theo, hãy tạo một phương thức có tên fetchAllLastNameByLocationUsedCursor trong Giao diện EmployeeRepositoryCustom và EmployeeRepositoryCustomImpl
Nhân viênKho lưu trữ Tùy chỉnh
spring.data.mongodb.authentication-database=admin spring.data.mongodb.username=root spring.data.mongodb.password=root spring.data.mongodb.database=baotrung spring.data.mongodb.port=27017 spring.data.mongodb.host=localhost4
Impl tùy chỉnh EmployeeRepository
Tiến hành tìm tất cả các LastName dựa trên vị trí bằng Cursor
server.port=8989 spring.data.mongodb.uri=mongodb://root:[email protected]:27017/BaoTrung spring.jpa.show-sql=true logging.level.org.springframework.data.mongodb.core.MongoTemplate=DEBUG logging.level.org.springframework.web = DEBUG9
Thay vì sử dụng các Lớp nhân viên để thực hiện ánh xạ, BasicDBObject thực hiện đọc trực tiếp vào Bson với tên trường là vị trí, MongoClient xác định các kết nối như tên máy chủ, cổng, tên cơ sở dữ liệu. Phía trên tên máy chủ là localHost, cổng là 27017 và tên cơ sở dữ liệu là BaoTrung. Ở đây chúng ta sử dụng lớp DBCollection để nhận bộ sưu tập trực tiếp từ MongoClient. Bộ sưu tập được up ở đây là Nhân viên. Thực hiện tạo một Set chứa các LastName mong muốn trả về. Con trỏ con trỏ = coll. tìm [truy vấn]; . Các phương thức như con trỏ. hasNext[] và con trỏ. next[] dùng để thực hiện tuần tự tìm kiếm trong các bảng ghi. Last Name. ví dụ thêm [[[Chuỗi]. get[“Họ”]]];
Kết quả khi thực hiện cuộc gọi api
Đăng nhập vào mùa xuân
spring.data.mongodb.authentication-database=admin spring.data.mongodb.username=root spring.data.mongodb.password=root spring.data.mongodb.database=baotrung spring.data.mongodb.port=27017 spring.data.mongodb.host=localhost0
Nhìn vào nhật ký có thể thấy bất kỳ Spring Data nào MongoDb đã k còn phân tích cú pháp ra các Pipeline nữa mà công việc thực hiện hoàn toàn dựa trên thao tác con trỏ trên bộ nhớ của mongoDB và trả về kết quả
Kết luận
Qua bài viết trên , mình đã giới thiệu cách sử dụng Aggregation trong spring, cách sử dụng mongoTemplate và Con trỏ. Sự khác nhau và khi nào nên sử dụng Cursor khi nào không. Hy vọng sẽ giúp mọi người hiểu thêm về Tổng hợp và tính toán tổng hợp vào dự án. Hẹn gặp lại mọi người ở các bài viết tiếp theo