Hướng dẫn aggregate mongodb là gì

1. Aggregation overview

Aggregation 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( [ {  }, {  }, ..., {  } ], {  } );

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à orderscustomers.

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ư WHEREHAVING trong SQL.

Cú pháp:

{ $match: {  } }

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: {  } }

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).
  • : <1 or true>: field X sẽ xuất hiện trong output document.
  • : : 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:  }

Trong đó:

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$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$skip tương tự như LIMITOFFSET trong SQL.

Cú pháp:

{ $limit:  }
{ $skip:  }

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: { : , :  ... } }

Trong đó, 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: , // Group By Expression
      : {  :  },
      ...
    }
 }

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:  }

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: ,
       localField: ,
       foreignField: ,
       as: 
     }
}

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 *, 
FROM collection
WHERE  IN (SELECT *
                               FROM 
                               WHERE = );

Ví dụ:

Mình sẽ join orderscustomers để 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 operator

Trong 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:

  1. Lọc tất cả các order có statuscompleted.
  2. Gom nhóm các order có được ở bước 1 theo cust_id và tính tổng amount.
  3. 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"
}

Hướng dẫn aggregate mongodb là gì

30 bài viết.

282 người follow

{{userFollowed ? 'Following' : 'Follow'}}

Cùng một tác giả

Hướng dẫn aggregate mongodb là gì

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

Hướng dẫn aggregate mongodb là gì

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

Hướng dẫn aggregate mongodb là gì

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

Hướng dẫn aggregate mongodb là gì

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

Hướng dẫn aggregate mongodb là gì

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

Hướng dẫn aggregate mongodb là gì

0 0

https://grokonez.com/nodejs/nodejsexpressrestapiuploadimportcsvfiledatatomongodbusingcsvtojsonmulter Nodejs Express RestAPI – Upload/Import CSV fi...

0 0