1. Aggregation overviewAggregation là một framework tổng hợp dữ liệu của MongoDB. Aggregation được xây dựng dựa trên mô hình xử lý dữ liệu dưới dạng pipeline. Aggregation pipeline bao gồm nhiều stage. Trong mỗi stage, chúng ta sử dụng một
aggregation operator để biến đổi dữ liệu của các input document. Các output document của stage phía trước sẽ là input document của stage ngay sau. Các aggregation operator có thể được sử dụng nhiều lần trong pipeline, ngoại trừ $out , $merge , và $geoNear . Điểm mạnh của aggregation framework là: - Xử lý nhanh và mạnh
mẽ với lượng ít băng thông.
- Giải quyết được các yêu cầu phức tạp.
- Có thể làm việc với dữ liệu lớn.
MongoDB cung cấp phương thức db.collection.aggregate() để chạy aggregation pipeline. Cú pháp: db.userCollection.aggregate( [ { <stage 1> }, { <stage 2> }, ..., { <stage N> } ], { <options> } );
Trong đó: - Các stage được đặt trong một array theo thứ tự thực hiện trước sau.
- Các option là tùy chọn, không nhất thiết phải có.
...
Để minh họa cho các operator, mình sẽ sử dụng 2 collection là orders và customers . Collection orders : /* 1 */
{
"_id" : ObjectId("5dfed89743e6fed50628907c"),
"cust_id" : "A123",
"products" : [
"apple",
"lemon"
],
"amount" : 500,
"status" : "completed"
}
/* 2 */
{
"_id" : ObjectId("5dfed8a643e6fed50628908a"),
"cust_id" : "B456",
"products" : [
"lemon"
],
"amount" : 100,
"status" : "processing"
}
/* 3 */
{
"_id" : ObjectId("5dfed8b043e6fed50628908f"),
"cust_id" : "B456",
"products" : [
"apple",
"orange"
],
"amount" : 300,
"status" : "completed"
}
/* 4 */
{
"_id" : ObjectId("5dfed8b943e6fed506289094"),
"cust_id" : "C789",
"products" : [
"apple",
"lemon",
"orange"
],
"amount" : 800,
"status" : "completed"
}
/* 5 */
{
"_id" : ObjectId("5dfed8c343e6fed506289097"),
"cust_id" : "A123",
"products" : [
"apple"
],
"amount" : 250,
"status" : "completed"
}
Collection customers : /* 1 */
{
"_id": "A123",
"name": "Alice"
}
/* 2 */
{
"_id": "B456",
"name": "Bob"
}
/* 3 */
{
"_id": "C789",
"name": "Carol"
}
2. $match $match được dùng để lọc các document theo một điều kiện nào đó. $match tương tự như WHERE và HAVING trong SQL.
Cú pháp: { $match: { <query> } }
Cú pháp query của $match y hệt cú pháp của
read operation query (tương tự như find() ). Ví dụ: Lọc các order của customer có ID là A123: db.orders.aggregate([
{
$match: {
cust_id: "A123"
}
}
])
=> Kết quả: /* 1 */
{
"_id" : ObjectId("5dfed89743e6fed50628907c"),
"cust_id" : "A123",
"products" : [
"apple",
"lemon"
],
"amount" : 500,
"status" : "completed"
}
/* 2 */
{
"_id" : ObjectId("5dfed8c343e6fed506289097"),
"cust_id" : "A123",
"products" : [
"apple"
],
"amount" : 250,
"status" : "completed"
}
3. $project $project được dùng để chỉ định các field sẽ xuất hiện trong output document. Đó có thể là các field đã tồn tại trong input document, hoặc cũng có thể là các field được tính toán mới. $project tương tự
như SELECT trong SQL.
Cú pháp: { $project: { <specification(s)> } }
Trong đó: specification có thể có các dạng sau:
-
_id: <0 or false> : field _id sẽ không xuất hiện trong output document (mặc định _id luôn xuất hiện trong output document). -
<field X>: <1 or true> : field X sẽ xuất hiện trong output document. -
<field X>: <expression> : field X sẽ được tính toán dựa trên một expression nào đó.
Ví dụ: db.orders.aggregate([
{
$project: {
_id: 0,
cust_id: 1,
new_amount: { $add: ["$amount", 100] }
}
}
])
=> Kết quả: /* 1 */
{
"cust_id" : "A123",
"new_amount" : 600.0
}
/* 2 */
{
"cust_id" : "B456",
"new_amount" : 200.0
}
/* 3 */
{
"cust_id" : "B456",
"new_amount" : 400.0
}
/* 4 */
{
"cust_id" : "C789",
"new_amount" : 900.0
}
/* 5 */
{
"cust_id" : "A123",
"new_amount" : 350.0
}
4. $count $count mới xuất
hiện trong MongoDB version 3.4. $count trả về thêm trong output một field X chứa tổng số input document.
Cú pháp:
{ $count: <string> }
Trong đó: <string> là tên của field X, phải khác rỗng, không được bắt đầu bằng ký tự $ và không được bao gồm ký tự . .
Ví dụ: db.orders.aggregate([
{
$count: "total"
}
])
=> Kết quả: /* 1 */
{
"total" : 5
}
5. $limit và $skip $limit được dùng để giới hạn số lượng output document. $skip được dùng để chỉ định số lượng document sẽ bị bỏ qua
trong output (tính từ document đầu tiên). $limit và $skip tương tự như LIMIT và OFFSET trong SQL.
Cú pháp: { $limit: <positive integer> }
{ $skip: <positive integer> }
Ví dụ: Lấy order thứ 3 và thứ 4: db.orders.aggregate([
{
$skip: 2
},
{
$limit: 2
}
])
=> Kết quả: /* 1 */
{
"_id" : ObjectId("5dfed8b043e6fed50628908f"),
"cust_id" : "B456",
"products" : [
"apple",
"orange"
],
"amount" : 300,
"status" : "completed"
}
/* 2 */
{
"_id" : ObjectId("5dfed8b943e6fed506289094"),
"cust_id" : "C789",
"products" : [
"apple",
"lemon",
"orange"
],
"amount" : 800,
"status" : "completed"
}
6. $sort $sort được dùng để sắp xếp các document trong output theo một tiêu chí nào đó. $sort tương tự như ORDER BY trong SQL.
Cú pháp: { $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }
Trong đó, <sort order> có thể có các giá trị sau: -
1 : sắp
xếp theo thứ tự tăng dần -
-1 : sắp xếp theo thứ tự giảm dần
Ví dụ: Sắp xếp các order theo thứ tự giảm dần của amount: db.orders.aggregate([
{
$sort: { amount: -1 }
}
])
=> Kết quả: /* 1 */
{
"_id" : ObjectId("5dfed8b943e6fed506289094"),
"cust_id" : "C789",
"products" : [
"apple",
"lemon",
"orange"
],
"amount" : 800,
"status" : "completed"
}
/* 2 */
{
"_id" : ObjectId("5dfed89743e6fed50628907c"),
"cust_id" : "A123",
"products" : [
"apple",
"lemon"
],
"amount" : 500,
"status" : "completed"
}
/* 3 */
{
"_id" : ObjectId("5dfed8b043e6fed50628908f"),
"cust_id" : "B456",
"products" : [
"apple",
"orange"
],
"amount" : 300,
"status" : "completed"
}
/* 4 */
{
"_id" : ObjectId("5dfed8c343e6fed506289097"),
"cust_id" : "A123",
"products" : [
"apple"
],
"amount" : 250,
"status" : "completed"
}
/* 5 */
{
"_id" : ObjectId("5dfed8a643e6fed50628908a"),
"cust_id" : "B456",
"products" : [
"lemon"
],
"amount" : 100,
"status" : "processing"
}
7. $group $group được dùng để gom nhóm các input document theo expression _id . Mỗi nhóm tương ứng với một output document. Trong $group , chúng ta có thể sử dụng các
accumulator expression như $sum , $avg , $max , $min , ...
$group tương tự như GROUP BY trong SQL.
Cú pháp: {
$group:
{
_id: <expression>, // Group By Expression
<field1>: { <accumulator1> : <expression1> },
...
}
}
Nếu _id được set bằng null , MongoDB sẽ query tất cả các input document. Ví dụ: Gom nhóm các order theo cust_id , đồng thời tính tổng amount của từng cust_id : db.orders.aggregate([
{
$group: {
_id: "$cust_id",
total: { $sum: "$amount" }
}
}
])
=> Kết quả: /* 1 */
{
"_id" : "B456",
"total" : 400
}
/* 2 */
{
"_id" : "C789",
"total" : 800
}
/* 3 */
{
"_id" : "A123",
"total" : 750
}
8. $unwind $unwind được dùng để phân tách giá trị của một array field trong các input document. Nếu như array field của một input document có N phần tử thì trong output sẽ có N document.
Cú pháp: { $unwind: <field path> }
Ví dụ: Mình sẽ thử áp dụng $unwind với array field products để xem kết quả nó sẽ như thế nào: db.orders.aggregate([
{
$unwind: "$products"
}
])
=> Kết quả: /* 1 */
{
"_id" : ObjectId("5dfed89743e6fed50628907c"),
"cust_id" : "A123",
"products" : "apple",
"amount" : 500,
"status" : "completed"
}
/* 2 */
{
"_id" : ObjectId("5dfed89743e6fed50628907c"),
"cust_id" : "A123",
"products" : "lemon",
"amount" : 500,
"status" : "completed"
}
/* 3 */
{
"_id" : ObjectId("5dfed8a643e6fed50628908a"),
"cust_id" : "B456",
"products" : "lemon",
"amount" : 100,
"status" : "processing"
}
/* 4 */
{
"_id" : ObjectId("5dfed8b043e6fed50628908f"),
"cust_id" : "B456",
"products" : "apple",
"amount" : 300,
"status" : "completed"
}
/* 5 */
{
"_id" : ObjectId("5dfed8b043e6fed50628908f"),
"cust_id" : "B456",
"products" : "orange",
"amount" : 300,
"status" : "completed"
}
/* 6 */
{
"_id" : ObjectId("5dfed8b943e6fed506289094"),
"cust_id" : "C789",
"products" : "apple",
"amount" : 800,
"status" : "completed"
}
/* 7 */
{
"_id" : ObjectId("5dfed8b943e6fed506289094"),
"cust_id" : "C789",
"products" : "lemon",
"amount" : 800,
"status" : "completed"
}
/* 8 */
{
"_id" : ObjectId("5dfed8b943e6fed506289094"),
"cust_id" : "C789",
"products" : "orange",
"amount" : 800,
"status" : "completed"
}
/* 9 */
{
"_id" : ObjectId("5dfed8c343e6fed506289097"),
"cust_id" : "A123",
"products" : "apple",
"amount" : 250,
"status" : "completed"
}
9. $lookup $lookup cho phép chúng ta thực hiện một phép left outer join giữa hai collection
trong cùng một database. Với mỗi input document, $lookup sẽ thêm một array field chứa các phần tử matching với collection được join.
Cú pháp: {
$lookup:
{
from: <collection to join>,
localField: <field from the input documents>,
foreignField: <field from the documents of the "from" collection>,
as: <output array field>
}
}
Trong đó: -
from collection không thể bị shard. -
as có thể có tên bất kỳ, nhưng nếu một field nào đó trong document đã có tên như vậy thì giá trị của field đó sẽ bị ghi đè.
$lookup tương đương với đoạn SQL sau:
SELECT *, <output array field>
FROM collection
WHERE <output array field> IN (SELECT *
FROM <collection to join>
WHERE <foreignField>= <collection.localField>);
Ví dụ: Mình sẽ join orders và customers để bổ sung thêm thông tin của customer trong từng order: db.orders.aggregate([
{
$lookup: {
from: "customers",
localField: "cust_id",
foreignField: "_id",
as: "customer"
}
}
])
=> Kết quả: /* 1 */
{
"_id" : ObjectId("5dfed89743e6fed50628907c"),
"cust_id" : "A123",
"products" : [
"apple",
"lemon"
],
"amount" : 500,
"status" : "completed",
"customer" : [
{
"_id" : "A123",
"name" : "Alice"
}
]
}
/* 2 */
{
"_id" : ObjectId("5dfed8a643e6fed50628908a"),
"cust_id" : "B456",
"products" : [
"lemon"
],
"amount" : 100,
"status" : "processing",
"customer" : []
}
/* 3 */
{
"_id" : ObjectId("5dfed8b043e6fed50628908f"),
"cust_id" : "B456",
"products" : [
"apple",
"orange"
],
"amount" : 300,
"status" : "completed",
"customer" : []
}
/* 4 */
{
"_id" : ObjectId("5dfed8b943e6fed506289094"),
"cust_id" : "C789",
"products" : [
"apple",
"lemon",
"orange"
],
"amount" : 800,
"status" : "completed",
"customer" : [
{
"_id" : "C789",
"name" : "Carol"
}
]
}
/* 5 */
{
"_id" : ObjectId("5dfed8c343e6fed506289097"),
"cust_id" : "A123",
"products" : [
"apple"
],
"amount" : 250,
"status" : "completed",
"customer" : [
{
"_id" : "A123",
"name" : "Alice"
}
]
}
10. Kết hợp các aggregation operatorTrong phần này, chúng ta sẽ kết hợp các aggregation operator trong một pipeline. Mình sẽ minh họa thông qua 2 ví dụ. Ví dụ 1 Yêu cầu: - Lọc tất cả các order có
status là completed . - Gom nhóm các order có được ở bước 1 theo
cust_id và
tính tổng amount . - Sắp xếp theo tổng amount giảm dần.
db.orders.aggregate([
{
$match: {
status: "completed"
}
},
{
$group: {
_id: "$cust_id",
total: { $sum: "$amount" }
}
},
{
$sort: { "total": -1 }
}
])
=> Kết quả: /* 1 */
{
"_id" : "C789",
"total" : 800
}
/* 2 */
{
"_id" : "A123",
"total" : 750
}
/* 3 */
{
"_id" : "B456",
"total" : 300
}
Ví dụ 2 Tiếp tục ví dụ 1, chúng ta sẽ bổ sung thêm customer name cho các output document. Các bạn lưu ý chúng ta sẽ chỉ bổ sung customer name mà thôi, còn customer ID thì chúng ta đã lưu trong _id rồi. db.orders.aggregate([
{
$match: {
status: "completed"
}
},
{
$group: {
_id: "$cust_id",
total: { $sum: "$amount" }
}
},
{
$sort: { "total": -1 }
},
{
$lookup: {
from: "customers",
localField: "_id",
foreignField: "_id",
as: "customer"
}
},
{
$project: {
total: 1,
cust_name: "$customer.name"
}
},
{
$unwind: "$cust_name"
}
])
=> Kết quả: /* 1 */
{
"_id" : "C789",
"total" : 800,
"cust_name" : "Carol"
}
/* 2 */
{
"_id" : "A123",
"total" : 750,
"cust_name" : "Alice"
}
/* 3 */
{
"_id" : "B456",
"total" : 300,
"cust_name" : "Bob"
}
30 bài viết. 282 người follow {{userFollowed ? 'Following' : 'Follow'}} Cùng một tác giả 62 42 MyContact là một ứng dụng mà mình thường viết mỗi khi học một ngôn ngữ hay công nghệ mới. MyContact chỉ là một ứng dụng CRUD đơn giản, cho phép ngư... 62 42 49 17 Hướng dẫn lập trình
Spring Security Trong bài viết lần này, mình sẽ giúp các bạn bước đầu tìm hiểu (Link) thông qua xây dựng các chức năng: Đăng ... 49 17 23 0 Trước đây khi mới học Spring, mình thường nhảy thẳng lên tìm hiểu các project như Spring MVC hay Spring Boot để viết ứng dụng, thỉnh thoảng mới ngó... 23 0
Bài viết liên quan 45 7 Giới thiệu MongoDB là một giải pháp nosql database. Data được lưu ở dạng các bson document. Hỗ trợ vertical scaling và horizontal scaling, dynamic... 45 7 31 13 Quá trình lột xác ngoạn mục của một hệ thống cổ lỗ sĩ khi được thiết kế cẩn thận: 1 usecase thành công của việc áp dụng triệt để các phương pháp xử... 31 13 0 0 https://grokonez.com/nodejs/nodejsexpressrestapiuploadimportcsvfiledatatomongodbusingcsvtojsonmulter Nodejs Express RestAPI – Upload/Import CSV fi... 0 0 |