Professional Documents
Culture Documents
1/. Aggregation:
https://www.geeksforgeeks.org/aggregation-in-mongodb/
A/. 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:
Các stage được đặt trong một array [ ] theo thứ tự thực hiện trước sau.
Các options là tùy chọn, không nhất thiết phải có.
MongoDB cung cấp ba cách để thực hiện tổng hợp:
Aggregation pipeline
Map-reduce function
Single-purpose aggregation
Trong MongoDB, Aggregation pipeline bao gồm các giai đoạn và mỗi stage (giai đoạn) sẽ
biến đổi tài liệu. Hay nói cách khác, Aggregation pipeline là một pipeline nhiều giai đoạn,
vì vậy ở mỗi trạng thái, các tài liệu được lấy làm đầu vào và tạo ra bộ tài liệu kết quả bây
giờ ở stage tiếp theo (có id) các tài liệu kết quả được lấy làm đầu vào và tạo ra đầu ra… ,
quá trình này đang diễn ra cho đến stage cuối cùng. Các stage pipeline cơ bản cung cấp các
bộ lọc sẽ thực hiện giống như các truy vấn và việc chuyển đổi tài liệu sẽ sửa đổi tài liệu kết
quả và pipeline khác cung cấp các công cụ để nhóm và phân loại document.
Sau đây là các pipeline stage có thể có các phép toán tổng hợp:
$project: chọn một số trường cụ thể từ một tập hợp.
1
$match: Đây là một hoạt động chọn lọc. do đó, điều này có thể làm giảm số lượng
document được cung cấp làm đầu vào cho giai đoạn tiếp theo.
$group: thực hiện gom nhóm.
$sort: Sắp xếp các document.
$skip: bỏ qua số lượng document nhất định.
$limit: giới hạn số lượng document cần xem, theo số lượng nhất định bắt đầu từ các
vị trí hiện tại.
$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 sử dụng để chia một Document đang sử dụng mảng thành
nhiều Document. Sử dụng hoạt động này sẽ tạo một số lượng Document cho bước
tiếp theo.).
Cú pháp của $group:
{
$group:
{
_id: <expression>, // Group By Expression
<field1>: { <accumulator1> : <expression1> },
...
}
}
Vd: sinh viên xem hình sau để hiểu ý nghĩa của Aggregate pipeline.
Trong ví dụ bằng hình ta thấy: trước tiên, giai đoạn $ match lọc tài liệu theo giá trị trong
trường class, là “first-class” và chuyển document sang giai đoạn thứ hai. Trong Giai đoạn
thứ hai, giai đoạn nhóm $ group các document theo trường “id” để tính tổng “fare” (giá vé)
cho mỗi id duy nhất.
2
Vd: tạo collection db3, tạo document train, thực hiện phép aggregate 2 stage
> use db3
switched to db db3
> db.createCollection("train") ‘tạo collection
{ "ok" : 1 }
> db.train.insertMany([ ‘tạo document
... {id: "181", class: "first-class", fare: 1200},
... {id: "181", class: "first-class", fare: 1000},
... {id: "181", class: "second-class", fare: 1000},
... {id: "167", class: "first-class", fare: 1200},
... {id: "167", class: "second-class", fare: 1500}])
{
"acknowledged" : true,
3
"insertedIds" : [
ObjectId("60bcc55cf95ca5f2be008870"),
ObjectId("60bcc55cf95ca5f2be008871"),
ObjectId("60bcc55cf95ca5f2be008872"),
ObjectId("60bcc55cf95ca5f2be008873"),
ObjectId("60bcc55cf95ca5f2be008874")
]
}
> db.train.find().pretty()
{
"_id" : ObjectId("60bcc55cf95ca5f2be008870"),
"id" : "181",
"class" : "first-class",
"fare" : 1200
}
{
"_id" : ObjectId("60bcc55cf95ca5f2be008871"),
"id" : "181",
"class" : "first-class",
"fare" : 1000
}
{
"_id" : ObjectId("60bcc55cf95ca5f2be008872"),
"id" : "181",
"class" : "second-class",
"fare" : 1000
}
{
"_id" : ObjectId("60bcc55cf95ca5f2be008873"),
"id" : "167",
4
"class" : "first-class",
"fare" : 1200
}
{
"_id" : ObjectId("60bcc55cf95ca5f2be008874"),
"id" : "167",
"class" : "second-class",
"fare" : 1500
}
‘nhóm theo id và tính tổng theo fare
> db.train.aggregate([ {$group: { _id: "$id", Tổng: {$sum: "$fare"}}} ])
{ "_id" : "167", "Tổng" : 2700 }
{ "_id" : "181", "Tổng" : 3200 }
5
Vd: tạo collection Students, nhập 7 document
> db.createCollection("Students")
{ "ok" : 1 }
> db.Students.insertMany([
... {id: 1, name: "Nguyễn Văn An", age: 22, sec: "1", subjects: ["Math", "IT"]},
... {id: 2, name: "Lê Thị Bé", age: 23, sec: "1", subjects: ["Math", "IT", "English"]},
... {id: 3, name: "Ngô Thị Kim Chi", age: 21, sec: "1", subjects: ["Math", "English"]}])
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("60bcdf90983baba85e0e349c"),
ObjectId("60bcdf90983baba85e0e349d"),
ObjectId("60bcdf90983baba85e0e349e")
]
}
> db.Students.insertMany([
... {id: 501, name: "Phan Kim Hương", age: 22, sec: "2", subjects: ["AI", "Software
Testing"]},
... {id: 502, name: "Nguyễn Văn Tài", age: 28, sec: "2", subjects: ["Big data", "Data
mining"]},
... {id: 503, name: "Ngô Thị Hòa", age: 24, sec: "2", subjects: ["AI", "Big data"]},
... {id: 801, name: "Nguyễn Văn Hùng", age: 25, sec: "3", subjects: ["English", "Big
data"]}])
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("60bce0d9983baba85e0e349f"),
ObjectId("60bce0d9983baba85e0e34a0"),
ObjectId("60bce0d9983baba85e0e34a1"),
ObjectId("60bce0d9983baba85e0e34a2")
]
6
}
> db.Students.find().pretty()
{
"_id" : ObjectId("60bcdf90983baba85e0e349c"),
"id" : 1,
"name" : "Nguyễn Văn An",
"age" : 22,
"sec" : "1",
"subjects" : [
"Math",
"IT"
]
}
{
"_id" : ObjectId("60bcdf90983baba85e0e349d"),
"id" : 2,
"name" : "Lê Thị Bé",
"age" : 23,
"sec" : "1",
"subjects" : [
"Math",
"IT",
"English"
]
}
{
"_id" : ObjectId("60bcdf90983baba85e0e349e"),
"id" : 3,
"name" : "Ngô Thị Kim Chi",
"age" : 21,
7
"sec" : "1",
"subjects" : [
"Math",
"English"
]
}
{
"_id" : ObjectId("60bce0d9983baba85e0e349f"),
"id" : 501,
"name" : "Phan Kim Hương",
"age" : 22,
"sec" : "2",
"subjects" : [
"AI",
"Software Testing"
]
}
{
"_id" : ObjectId("60bce0d9983baba85e0e34a0"),
"id" : 502,
"name" : "Nguyễn Văn Tài",
"age" : 28,
"sec" : "2",
"subjects" : [
"Big data",
"Data mining"
]
}
{
"_id" : ObjectId("60bce0d9983baba85e0e34a1"),
8
"id" : 503,
"name" : "Ngô Thị Hòa",
"age" : 24,
"sec" : "2",
"subjects" : [
"AI",
"Big data"
]
}
{
"_id" : ObjectId("60bce0d9983baba85e0e34a2"),
"id" : 801,
"name" : "Nguyễn Văn Hùng",
"age" : 25,
"sec" : "3",
"subjects" : [
"English",
"Big data"
]
}
‘tính tổng số sinh viên học kỳ 1
> db.Students.aggregate([ {$match: {sec: "1"}}, {$count: "Tổng số sinh viên học kỳ
1"}])
{ "Tổng số sinh viên học kỳ 1" : 3 }
‘nhóm sinh viên theo học kỳ, tính tổng số sinh viên theo nhóm và lấy tuổi lớn nhất
> db.Students.aggregate([ {$group: {_id: "$sec", "Tổng số sinh viên": {$sum: 1},
"Tuổi lớn nhất": {$max: "$age"}}}])
{ "_id" : "3", "Tổng số sinh viên" : 1, "Tuổi lớn nhất" : 25 }
{ "_id" : "1", "Tổng số sinh viên" : 3, "Tuổi lớn nhất" : 23 }
{ "_id" : "2", "Tổng số sinh viên" : 3, "Tuổi lớn nhất" : 28 }
9
‘phép chiếu trên cột id, name
> db.Students.aggregate([
... {$project: {_id: 0, ‘ẩn cột _id
... id: 1, name: 1}} ‘hiện cột id, name
... ])
{ "id" : 1, "name" : "Nguyễn Văn An" }
{ "id" : 2, "name" : "Lê Thị Bé" }
{ "id" : 3, "name" : "Ngô Thị Kim Chi" }
{ "id" : 501, "name" : "Phan Kim Hương" }
{ "id" : 502, "name" : "Nguyễn Văn Tài" }
{ "id" : 503, "name" : "Ngô Thị Hòa" }
{ "id" : 801, "name" : "Nguyễn Văn Hùng" }
10
{ "_id" : ObjectId("60bcdf90983baba85e0e349d"), "id" : 2, "name" : "Lê Thị Bé", "age" :
23, "sec" : "1", "subjects" : [ "Math", "IT", "English" ] }
{ "_id" : ObjectId("60bce0d9983baba85e0e34a1"), "id" : 503, "name" : "Ngô Thị Hòa",
"age" : 24, "sec" : "2", "subjects" : [ "AI", "Big data" ] }
{ "_id" : ObjectId("60bce0d9983baba85e0e34a2"), "id" : 801, "name" : "Nguyễn Văn
Hùng", "age" : 25, "sec" : "3", "subjects" : [ "English", "Big data" ] }
{ "_id" : ObjectId("60bce0d9983baba85e0e34a0"), "id" : 502, "name" : "Nguyễn Văn Tài",
"age" : 28, "sec" : "2", "subjects" : [ "Big data", "Data mining" ] }
‘chọn các sv học kỳ 1 (sec = 1), sắp xếp theo tuổi và chỉ lấy 1 document
> db.Students.aggregate([ {$match: {"sec": "1"}}, {$sort: {"age": 1}}, {$limit: 2}])
{ "_id" : ObjectId("60bcdf90983baba85e0e349e"), "id" : 3, "name" : "Ngô Thị Kim Chi",
"age" : 21, "sec" : "1", "subjects" : [ "Math", "English" ] }
{ "_id" : ObjectId("60bcdf90983baba85e0e349c"), "id" : 1, "name" : "Nguyễn Văn An",
"age" : 22, "sec" : "1", "subjects" : [ "Math", "IT" ] }
‘ta có mảng subjects (các môn học), thực hiện phân giải dữ liệu theo cấu trúc mảng
> db.Students.aggregate([
... {$unwind: "$subjects"}])
{ "_id" : ObjectId("60bcdf90983baba85e0e349c"), "id" : 1, "name" : "Nguyễn Văn An",
"age" : 22, "sec" : "1", "subjects" : "Math" }
{ "_id" : ObjectId("60bcdf90983baba85e0e349c"), "id" : 1, "name" : "Nguyễn Văn An",
"age" : 22, "sec" : "1", "subjects" : "IT" }
{ "_id" : ObjectId("60bcdf90983baba85e0e349d"), "id" : 2, "name" : "Lê Thị Bé", "age" :
23, "sec" : "1", "subjects" : "Math" }
{ "_id" : ObjectId("60bcdf90983baba85e0e349d"), "id" : 2, "name" : "Lê Thị Bé", "age" :
23, "sec" : "1", "subjects" : "IT" }
{ "_id" : ObjectId("60bcdf90983baba85e0e349d"), "id" : 2, "name" : "Lê Thị Bé", "age" :
23, "sec" : "1", "subjects" : "English" }
{ "_id" : ObjectId("60bcdf90983baba85e0e349e"), "id" : 3, "name" : "Ngô Thị Kim Chi",
"age" : 21, "sec" : "1", "subjects" : "Math" }
{ "_id" : ObjectId("60bcdf90983baba85e0e349e"), "id" : 3, "name" : "Ngô Thị Kim Chi",
"age" : 21, "sec" : "1", "subjects" : "English" }
{ "_id" : ObjectId("60bce0d9983baba85e0e349f"), "id" : 501, "name" : "Phan Kim Hương",
"age" : 22, "sec" : "2", "subjects" : "AI" }
{ "_id" : ObjectId("60bce0d9983baba85e0e349f"), "id" : 501, "name" : "Phan Kim Hương",
"age" : 22, "sec" : "2", "subjects" : "Software Testing" }
11
{ "_id" : ObjectId("60bce0d9983baba85e0e34a0"), "id" : 502, "name" : "Nguyễn Văn Tài",
"age" : 28, "sec" : "2", "subjects" : "Big data" }
{ "_id" : ObjectId("60bce0d9983baba85e0e34a0"), "id" : 502, "name" : "Nguyễn Văn Tài",
"age" : 28, "sec" : "2", "subjects" : "Data mining" }
{ "_id" : ObjectId("60bce0d9983baba85e0e34a1"), "id" : 503, "name" : "Ngô Thị Hòa",
"age" : 24, "sec" : "2", "subjects" : "AI" }
{ "_id" : ObjectId("60bce0d9983baba85e0e34a1"), "id" : 503, "name" : "Ngô Thị Hòa",
"age" : 24, "sec" : "2", "subjects" : "Big data" }
{ "_id" : ObjectId("60bce0d9983baba85e0e34a2"), "id" : 801, "name" : "Nguyễn Văn
Hùng", "age" : 25, "sec" : "3", "subjects" : "English" }
{ "_id" : ObjectId("60bce0d9983baba85e0e34a2"), "id" : 801, "name" : "Nguyễn Văn
Hùng", "age" : 25, "sec" : "3", "subjects" : "Big data" }
‘đếm số sinh viên
> db.Students.count()
7
‘hiển thị các tuổi của sinh viên (không lặp lại
> db.Students.distinct("age")
[ 21, 22, 23, 24, 25, 28 ]
‘bỏ qua 2 document đầu
> db.Students.aggregate([ {$skip: 2}])
{ "_id" : ObjectId("60bcdf90983baba85e0e349e"), "id" : 3, "name" : "Ngô Thị Kim Chi",
"age" : 21, "sec" : "1", "subjects" : [ "Math", "English" ] }
{ "_id" : ObjectId("60bce0d9983baba85e0e349f"), "id" : 501, "name" : "Phan Kim Hương",
"age" : 22, "sec" : "2", "subjects" : [ "AI", "Software Testing" ] }
{ "_id" : ObjectId("60bce0d9983baba85e0e34a0"), "id" : 502, "name" : "Nguyễn Văn Tài",
"age" : 28, "sec" : "2", "subjects" : [ "Big data", "Data mining" ] }
{ "_id" : ObjectId("60bce0d9983baba85e0e34a1"), "id" : 503, "name" : "Ngô Thị Hòa",
"age" : 24, "sec" : "2", "subjects" : [ "AI", "Big data" ] }
{ "_id" : ObjectId("60bce0d9983baba85e0e34a2"), "id" : 801, "name" : "Nguyễn Văn
Hùng", "age" : 25, "sec" : "3", "subjects" : [ "English", "Big data" ] }
12
Thực hiện phép nối bên ngoài bên trái với một collection trong cùng một cơ sở dữ liệu để
lọc trong các document từ collection đã kết hợp để xử lý. Đối với mỗi document đầu vào,
giai đoạn $ lookup sẽ thêm một trường Array (mảng) mới có các phần tử là các document
phù hợp từ collection đã kết hợp. Giai đoạn $ lookup chuyển các document được định hình
lại này sang giai đoạn tiếp theo.
Cú pháp:
db.collection_input.aggregate([
{
$lookup:
{
from: <collection to join>,
localField: <field from the input documents>,
foreignField: <field from the documents of the "from" collection>,
as: <output array field>
}
…
}
])
Tham khảo: https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/
Field Description
from Chỉ định collection trong cùng một cơ sở dữ liệu để thực hiện phép nối
(join). Collection này gọi là from collection.
localField Chỉ định field của collection_ input. $lookup thực hiện đối sánh trên
localField với ForeignField của collection từ from. Nếu collection_input
không chứa localField, $lookup sẽ coi filed có giá trị null cho các mục
đích phù hợp.
foreignField Chỉ định field ngoại từ from collection. $lookup thực hiện đối sánh trên
ForeignField với localField với collection_input. Nếu collection trong
from (from collection) không chứa ForeignField, $ lookup sẽ coi giá trị
là null cho các mục đích phù hợp.
as Chỉ định tên của output Array field mới để thêm vào collection_input.
13
Field Description
Output Array field mới chứa các dữ liệu phù hợp từ from collection. Nếu
tên được chỉ định đã tồn tại trong collection_input, field hiện có sẽ bị ghi
đè.
Thao tác $lookup sẽ tương ứng với câu lệnh SQL sau:
SELECT *, <output array field>
FROM collection_input
WHERE <output array field> IN (SELECT *
FROM <from collection>
WHERE <foreignField>= <collection.localField>);
14
"nRemoved" : 0,
"upserted" : [ ]
})
> db.Inventory.insert([
... { "_id" : 1, "sku" : "almonds", "description": "product 1", "instock" : 120 },
... { "_id" : 2, "sku" : "bread", "description": "product 2", "instock" : 80 },
... { "_id" : 3, "sku" : "cashews", "description": "product 3", "instock" : 60 },
... { "_id" : 4, "sku" : "pecans", "description": "product 4", "instock" : 70 },
... { "_id" : 5, "sku": null, "description": "Incomplete" },
... { "_id" : 6 }
... ])
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 6,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})
> db.Order.aggregate([
... {
... $lookup:
... {
... from: "Inventory",
... localField: "item",
... foreignField: "sku",
... as: "inventory_docs"
... }
15
... }
... ])
{ "_id" : 1, "item" : "almonds", "price" : 12, "quantity" : 2, "inventory_docs" : [ { "_id" : 1,
"sku" : "almonds", "description" : "product 1", "instock" : 120 } ] }
{ "_id" : 2, "item" : "pecans", "price" : 20, "quantity" : 1, "inventory_docs" : [ { "_id" : 4,
"sku" : "pecans", "description" : "product 4", "instock" : 70 } ] }
{ "_id" : 3, "inventory_docs" : [ { "_id" : 5, "sku" : null, "description" : "Incomplete" },
{ "_id" : 6 } ] }
‘Truy vấn trên tương đương với:
SELECT *, inventory_docs
FROM orders
WHERE inventory_docs IN (SELECT *
FROM inventory
WHERE sku= orders.item);
Vd: truy vấn dữ liệu từ 2 collection, có chứa mảng giá trị so khớp (sv so khớp dữ liệu để
hiểu)
> db.createCollection("Genres")
{ "ok" : 1 }
> db.createCollection("Movies")
{ "ok" : 1 }
> db.Genres.insertMany( [
... { _id: 1, title: "Notebook", genrelist: [ "comedy", "romance", "fiction" ]},
... { _id: 2, title: "Anabelle", genrelist: [ "horror", "fiction" ]}
... ])
{ "acknowledged" : true, "insertedIds" : [ 1, 2 ] }
> db.Movies.insertMany( [
... { _id: 1, name: "HarryPotter", "type": "fiction", rating: "A" },
... { _id: 2, name: "LOTR", "type": "fiction", rating: "D" },
... { _id: 3, name: "Witchcraft", "type": "horror", rating: "A" },
... { _id: 4, name: "panda", "type": "romance", rating: "A" },
16
... { _id: 5, name: "What is new", "type": "comedy", rating: "A" },
... { _id: 6, name: "Date", "type": "romance", rating: "D" }
... ])
{ "acknowledged" : true, "insertedIds" : [ 1, 2, 3, 4, 5, 6 ] }
> db.Genres.aggregate([
... {
... $lookup:
... {
... from : "Movies",
... localField : "genrelist", //mảng
... foreignField : "type",
... as : "movie"
... } } ] )
{ "_id" : 1, "title" : "Notebook", "genrelist" : [ "comedy", "romance", "fiction" ], "movie" :
[ { "_id" : 1, "name" : "HarryPotter", "type" : "fiction", "rating" : "A" }, { "_id" : 2, "name" :
"LOTR", "type" : "fiction", "rating" : "D" }, { "_id" : 4, "name" : "panda", "type" :
"romance", "rating" : "A" }, { "_id" : 5, "name" : "What is new", "type" : "comedy",
"rating" : "A" }, { "_id" : 6, "name" : "Date", "type" : "romance", "rating" : "D" } ] }
Để thực hiện các truy vấn con không tương quan giữa hai collection cũng như cho phép các
điều kiện join (nối) khác bên cạnh một kết hợp bình đẳng duy nhất, giai đoạn $lookup có
thêm các field như sau:
Tham khảo:
https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/
https://www.javatpoint.com/mongodb-aggregation-pipeline-operators
Field Description
18
Field Description
$mergeObjects Kết hợp nhiều document thành một document duy nhất.
20
o $cond: { if: '$applyDiscount', then: 0.9, else: 1 } }: điều kiện, nếu
$applyDiscount là true thì trả ra 0.9, còn lại trả ra 1.
o vars: gán biểu thức tính cho 2 biến: total và discounted.
o in: đặt biểu thức tính cho field finalTotal.
o $$total, $$discounted: tham chiếu đến 2 biến total và discounted (để tham
chiếu phải có $$ đứng trước biến)
‘Truy vấn này có dùng $pipeline để so khớp với môn thể thao basketball (bóng rổ) trong
tất cả document của collection Winners và chọn place và date, tạo ra một trường mới là
mảng win để lưu trữ tất cả các trận đấu trong mảng.
> db.Sports.aggregate([
…{ $lookup:{from: "Winners",
21
…pipeline: [{ $match: { sport: "basketball" } }, { $project: { _id: 0, date: { place:
"$place", date: "$date" } } }],
…as: "win"}
…}
…])
{ "_id" : 1, "student" : "Ann Aardvark", "sports" : [ "basketball", "Throwball" ], "win" :
[ { "date" : { "place" : 1, "date" : ISODate("2018-01-01T00:00:00Z") } }, { "date" :
{ "place" : 4, "date" : ISODate("2018-03-14T00:00:00Z") } }, { "date" : { "place" : 2, "date"
: ISODate("2018-07-15T00:00:00Z") } } ] }
{ "_id" : 2, "student" : "Zoe Zebra", "sports" : [ "Tennis", "TT" ], "win" : [ { "date" :
{ "place" : 1, "date" : ISODate("2018-01-01T00:00:00Z") } }, { "date" : { "place" : 4, "date"
: ISODate("2018-03-14T00:00:00Z") } }, { "date" : { "place" : 2, "date" : ISODate("2018-
07-15T00:00:00Z") } } ] }
//sinh viên dò và kiểm dữ liệu
22
"ok" : 0,
"errmsg" : "'newRoot' expression must evaluate to an object, but resulting value was:
MISSING. Type of resulting value: 'missing'. Input document: {}",
"code" : 40228,
"codeName" : "Location40228"
} : aggregate failed :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
doassert@src/mongo/shell/assert.js:18:14
_assertCommandWorked@src/mongo/shell/assert.js:639:17
assert.commandWorked@src/mongo/shell/assert.js:729:16
DB.prototype._runAggregate@src/mongo/shell/db.js:266:5
DBCollection.prototype.aggregate@src/mongo/shell/collection.js:1058:12
@(shell):1:1
‘Để tránh lỗi, ta có thể sử dụng $ mergeObjects để hợp nhất (merge) field name vào một số
field khác.
> db.Mycollection.aggregate([
... { $replaceRoot: { newRoot: { $mergeObjects: [ { _id: "$_id", first: "", last: "" },
"$name" ] } } }
... ])
{ "_id" : 1, "first" : "John", "last" : "Backus" }
{ "_id" : 2, "first" : "John", "last" : "McCarthy" }
{ "_id" : 3, "first" : "Grace", "last" : "Hopper" }
{ "_id" : 4, "first" : "", "last" : "" }
‘Ngoài ra, Ta có thể bỏ qua các tài liệu thiếu field name bằng cách bao gồm giai đoạn $
match để kiểm tra sự tồn tại của field trước khi chuyển document sang giai đoạn $
ReplaceRoot:
> db.Mycollection.aggregate([
... { $match: { name : { $exists: true, $not: { $type: "array" }, $type: "object" } } },
... { $replaceRoot: { newRoot: "$name" } }
... ])
{ "first" : "John", "last" : "Backus" }
23
{ "first" : "John", "last" : "McCarthy" }
{ "first" : "Grace", "last" : "Hopper" }
‘Hoặc có thể sử dụng biểu thức $ ifNull để chỉ định một số tài liệu khác là root; ví dụ:
> db.Mycollection.aggregate([
... { $replaceRoot: { newRoot: { $ifNull: [ "$name", { _id: "$_id", missingName:
true} ] } } }
... ])
{ "first" : "John", "last" : "Backus" }
{ "first" : "John", "last" : "McCarthy" }
{ "first" : "Grace", "last" : "Hopper" }
{ "_id" : 4, "missingName" : true }
25
}
‘Thao tác sau sẽ lấy các document nhúng có field diem.lythuyet lớn hơn hoặc bằng 8.5 lên
cấp cao nhất (dùng $unwind để chia một document đang sử dụng field Array thành nhiều
document)
> db.MonhocXYZ.aggregate( [
... { $unwind: "$diem" },
... { $match: { "diem.lythuyet" : { $gte: 8.5 } } },
... { $replaceRoot: { newRoot: "$diem" } }
... ] )
{ "test" : "Kỳ 2", "thuchanh" : 8.5, "lythuyet" : 9, "kynang" : 4 }
{ "test" : "Kỳ 3", "thuchanh" : 9.5, "lythuyet" : 8.5, "kynang" : 6 }
{ "test" : "Kỳ 2", "thuchanh" : 9, "lythuyet" : 9, "kynang" : 3 }
{ "test" : "Kỳ 3", "thuchanh" : 9, "lythuyet" : 8.5, "kynang" : 4 }
‘Thao tác sau sẽ lấy các document nhúng có field diem.thuchanh lớn hơn hoặc bằng 9.5
> db.MonhocXYZ.aggregate( [
... { $unwind: "$diem" },
... { $match: { "diem.thuchanh" : { $gte: 9.5 } } },
... { $replaceRoot: { newRoot: "$diem" } }
... ] )
{ "test" : "Kỳ 3", "thuchanh" : 9.5, "lythuyet" : 8.5, "kynang" : 6 }
27
... {
... $replaceRoot: { newRoot: { $mergeObjects: [ { $arrayElemAt: [ "$fromItems",
0 ] }, "$$ROOT" ] } }
... },
... { $project: { fromItems: 0 } }
... ])
{ "_id" : 1, "item" : "abc", "description" : "product 1", "instock" : 120, "price" : 12,
"ordered" : 2 }
{ "_id" : 2, "item" : "xyz", "description" : "product 3", "instock" : 60, "price" : 20, "ordered"
:1}
2/. Mapreduce:
Trong MongoDB, map-Reduce là một mô hình lập trình xử lý dữ liệu giúp thực hiện các
thao tác trên các Big Data (tập dữ liệu lớn) và tạo ra các kết quả tổng hợp. MongoDB cung
cấp hàm mapReduce () để thực hiện các thao tác rút gọn dữ liệu. Chức năng này có hai chức
năng chính, tức là chức năng Map và chức năng Reduce.
Hàm map được sử dụng để nhóm tất cả dữ liệu dựa trên cặp key-value (khóa-giá trị) và hàm
Reduce được sử dụng để thực hiện các thao tác trên dữ liệu được ánh xạ. Vì vậy, dữ liệu
được ánh xạ và rút gọn một cách độc lập trong các không gian khác nhau và sau đó được kết
hợp với nhau để có kết quả sẽ lưu vào bộ sưu tập mới được chỉ định.
Cú pháp:
>db.collection.example(
function() {emit(key, value);}, //Define map function
function(key,values) {return reduceFunction}, //Define reduce function
{
out: collection,
query: document,
sort: document,
limit: number
28
}
)
Map: Đây là một hàm JavaScript, được sử dụng để tạo các cặp khóa-giá trị.
Reduce: Một chức năng JavaScript sử dụng để nhóm tất cả các tài liệu có cùng một
khóa.
Out: Nó chỉ định vị trí của đầu ra truy vấn MapReduce.
Query: Chúng ta có thể sử dụng nó để chỉ định các tiêu chí lựa chọn để chọn tài liệu.
Sort: Sử dụng để chỉ định tiêu chí sắp xếp và các lệnh tùy chọn.
Limit: Nó chỉ định số lượng tài liệu được trả lại. Nó là một lệnh tùy chọn được sử
dụng.
Ví dụ:
Hàm mapReduce () này thường chỉ hoạt động trên các Big Data (tập dữ liệu lớn). Sử dụng
Map Reduce, bạn có thể thực hiện các phép toán tổng hợp như max, avg trên dữ liệu bằng
cách sử dụng một số khóa và nó tương tự như groupBy trong SQL. Nó thực hiện trên dữ
liệu một cách độc lập và song song. Hãy cố gắng hiểu mapReduce () bằng ví dụ với 4 bước
sau:
Vd: tạo database db4, collection Orders, chèn 09 thêm document
> use db4
> db.createCollection("Orders")
> db.Orders.insertMany([
…{cust_name: "Trần Thị Kim", or_date: new Date("2021-05-01"), amount: 120, items:
[{name: "Táo xanh", qty: 10, price: 12}], status: "A"},
…{cust_name: "Lê Thị Bé", or_date: new Date("2021-05-01"), amount: 200, items:
[{name: "Quít hồng", qty: 10, price: 10}, {name: "Táo vàng", qty: 10, price: 10}], status:
"A"},
…{cust_name: "Nguyễn Phú Đại", or_date: new Date("2021-05-03"), amount: 250, items:
[{name: "Sầu riêng", qty: 10, price: 20}, {name: "Thanh long trắng", qty: 5, price: 10}],
status: "A"},
…{cust_name: "Phạm Phú", or_date: new Date("2021-05-04"), amount: 500, items:
[{name: "Sầu riêng vàng", qty: 10, price: 50}], status: "B"},
29
…{cust_name: "Ngô Văn Lăng", or_date: new Date("2021-05-05"), amount: 350, items:
[{name: "Táo vàng", qty: 20, price: 10}, {name: "Táo đỏ", qty: 10, price: 10}, {name: "Ổi
tím", qty: 5, price: 10}], status: "A"},
…{cust_name: "Lê Thị Bé", or_date: new Date("2021-05-06"), amount: 150, items:
[{name: "Quít vàng", qty: 10, price: 15}], status: "B"},
…{cust_name: "Trần Thị Kim", or_date: new Date("2021-05-06"), amount: 200, items:
[{name: "Táo xanh", qty: 10, price: 12}, {name: "Ổi vàng", qty: 10, price: 8}], status: "A"},
{cust_name: "Ngô Văn Lăng", or_date: new Date("2021-05-07"), amount: 450, items:
[{name: "Sầu riêng đỏ", qty: 10, price: 15},{name: "Ổi hồng", qty: 10, price: 10}, {name:
"Táo đỏ", qty: 20, price: 10}], status: "P"},
…{cust_name: "Lê Thị Bé", or_date: new Date("2021-05-08"), amount: 200, items:
[{name: "Táo vàng", qty: 10, price: 10}, {name: "Sầu riêng", qty: 5, price: 20}], status: "P"}
…])
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("60beda1da164ce770305514d"),
ObjectId("60beda1da164ce770305514e"),
ObjectId("60beda1da164ce770305514f"),
ObjectId("60beda1da164ce7703055150"),
ObjectId("60beda1da164ce7703055151"),
ObjectId("60beda1da164ce7703055152"),
ObjectId("60beda1da164ce7703055153"),
ObjectId("60beda1da164ce7703055154"),
ObjectId("60beda1da164ce7703055155")
]
}
> db.Orders.find().pretty()
{
"_id" : ObjectId("60beda1da164ce770305514d"),
"cust_name" : "Trần Thị Kim",
"or_date" : ISODate("2021-05-01T00:00:00Z"),
30
"amount" : 120,
"items" : [
{
"name" : "Táo xanh",
"qty" : 10,
"price" : 12
}
],
"status" : "A"
}
{
"_id" : ObjectId("60beda1da164ce770305514e"),
"cust_name" : "Lê Thị Bé",
"or_date" : ISODate("2021-05-01T00:00:00Z"),
"amount" : 200,
"items" : [
{
"name" : "Quít hồng",
"qty" : 10,
"price" : 10
},
{
"name" : "Táo vàng",
"qty" : 10,
"price" : 10
}
],
"status" : "A"
}
{
31
"_id" : ObjectId("60beda1da164ce770305514f"),
"cust_name" : "Nguyễn Phú Đại",
"or_date" : ISODate("2021-05-03T00:00:00Z"),
"amount" : 250,
"items" : [
{
"name" : "Sầu riêng",
"qty" : 10,
"price" : 20
},
{
"name" : "Thanh long trắng",
"qty" : 5,
"price" : 10
}
],
"status" : "A"
}
{
"_id" : ObjectId("60beda1da164ce7703055150"),
"cust_name" : "Phạm Phú",
"or_date" : ISODate("2021-05-04T00:00:00Z"),
"amount" : 500,
"items" : [
{
"name" : "Sầu riêng vàng",
"qty" : 10,
"price" : 50
}
],
32
"status" : "B"
}
{
"_id" : ObjectId("60beda1da164ce7703055151"),
"cust_name" : "Ngô Văn Lăng",
"or_date" : ISODate("2021-05-05T00:00:00Z"),
"amount" : 350,
"items" : [
{
"name" : "Táo vàng",
"qty" : 20,
"price" : 10
},
{
"name" : "Táo đỏ",
"qty" : 10,
"price" : 10
},
{
"name" : "Ổi tím",
"qty" : 5,
"price" : 10
}
],
"status" : "A"
}
{
"_id" : ObjectId("60beda1da164ce7703055152"),
"cust_name" : "Lê Thị Bé",
"or_date" : ISODate("2021-05-06T00:00:00Z"),
33
"amount" : 150,
"items" : [
{
"name" : "Quít vàng",
"qty" : 10,
"price" : 15
}
],
"status" : "B"
}
{
"_id" : ObjectId("60beda1da164ce7703055153"),
"cust_name" : "Trần Thị Kim",
"or_date" : ISODate("2021-05-06T00:00:00Z"),
"amount" : 200,
"items" : [
{
"name" : "Táo xanh",
"qty" : 10,
"price" : 12
},
{
"name" : "Ổi vàng",
"qty" : 10,
"price" : 8
}
],
"status" : "A"
}
{
34
"_id" : ObjectId("60beda1da164ce7703055154"),
"cust_name" : "Ngô Văn Lăng",
"or_date" : ISODate("2021-05-07T00:00:00Z"),
"amount" : 450,
"items" : [
{
"name" : "Sầu riêng đỏ",
"qty" : 10,
"price" : 15
},
{
"name" : "Ổi hồng",
"qty" : 10,
"price" : 10
},
{
"name" : "Táo đỏ",
"qty" : 20,
"price" : 10
}
],
"status" : "P"
}
{
"_id" : ObjectId("60beda1da164ce7703055155"),
"cust_name" : "Lê Thị Bé",
"or_date" : ISODate("2021-05-08T00:00:00Z"),
"amount" : 200,
"items" : [
{
35
"name" : "Táo vàng",
"qty" : 10,
"price" : 10
},
{
"name" : "Sầu riêng",
"qty" : 5,
"price" : 20
}
],
"status" : "P"
}
‘thực hiện MapReduce theo các bước
‘Bước 1: định nghĩa hàm map_function1, có ánh xạ đến trường cust_name và amount
> var map_function1 = function(){
... emit(this.cust_name, this,amount);
... };
‘Bước 3: Thực hiện mapReduce trên tất cả các document trong collection Orders bằng cách
sử dụng hàm map_function1 và hàm reduce_function1, và xuất kết quả thực hiện ra
collection Ketqua1
> db.Orders.mapReduce( map_function1, reduce_function1, {out: "Ketqua1"} )
{ "result" : "Ketqua1", "ok" : 1 }
36
‘Bước 4: collection Ketqua1 đã được tạo ra và dùng phương thức find() để xem kết quả
> db.Ketqua1.find()
{ "_id" : "Nguyễn Phú Đại", "value" : 250 }
{ "_id" : "Phạm Phú", "value" : 500 }
{ "_id" : "Lê Thị Bé", "value" : 550 }
{ "_id" : "Trần Thị Kim", "value" : 320 }
{ "_id" : "Ngô Văn Lăng", "value" : 800 }
Hoặc xem kết quả được xắp xếp theo _id giảm dần
> db.Ketqua1.find().sort({_id: -1})
{ "_id" : "Trần Thị Kim", "value" : 320 }
{ "_id" : "Phạm Phú", "value" : 500 }
{ "_id" : "Ngô Văn Lăng", "value" : 800 }
{ "_id" : "Nguyễn Phú Đại", "value" : 250 }
{ "_id" : "Lê Thị Bé", "value" : 550 }
Hoặc xem kết quả được xắp xếp theo value tăng dần
> db.Ketqua1.find().sort({value: 1})
{ "_id" : "Nguyễn Phú Đại", "value" : 250 }
{ "_id" : "Trần Thị Kim", "value" : 320 }
{ "_id" : "Phạm Phú", "value" : 500 }
{ "_id" : "Lê Thị Bé", "value" : 550 }
{ "_id" : "Ngô Văn Lăng", "value" : 800 }
37
…{sohd: "1237", makh: "k01", ngay: new Date("2021-05-02"), ttien: 2400},
…{sohd: "1238", makh: "k03", ngay: new Date("2021-05-02"), ttien: 1500},
…{sohd: "1239", makh: "k05", ngay: new Date("2021-05-03"), ttien: 4800},
…{sohd: "1240", makh: "k04", ngay: new Date("2021-05-03"), ttien: 2500},
…{sohd: "1241", makh: "k02", ngay: new Date("2021-05-03"), ttien: 5000},
…{sohd: "1242", makh: "k01", ngay: new Date("2021-05-04"), ttien: 2600},
…{sohd: "1243", makh: "k05", ngay: new Date("2021-05-05"), ttien: 4100},
…{sohd: "1243", makh: "k01", ngay: new Date("2021-05-05"), ttien: 3600},
…{sohd: "1244", makh: "k03", ngay: new Date("2021-05-06"), ttien: 1200},
…{sohd: "1245", makh: "k01", ngay: new Date("2021-05-06"), ttien: 1400}
…])
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("60bf577730ef6451158dd341"),
ObjectId("60bf577730ef6451158dd342"),
ObjectId("60bf577730ef6451158dd343"),
ObjectId("60bf577730ef6451158dd344"),
ObjectId("60bf577730ef6451158dd345"),
ObjectId("60bf577730ef6451158dd346"),
ObjectId("60bf577730ef6451158dd347"),
ObjectId("60bf577730ef6451158dd348"),
ObjectId("60bf577730ef6451158dd349"),
ObjectId("60bf577730ef6451158dd34a"),
ObjectId("60bf577730ef6451158dd34b"),
ObjectId("60bf577730ef6451158dd34c"),
ObjectId("60bf577730ef6451158dd34d")
]
}
> db.BanHang.find().pretty()
38
{
"_id" : ObjectId("60bf577730ef6451158dd341"),
"sohd" : "1234",
"makh" : "k01",
"ngay" : ISODate("2021-05-01T00:00:00Z"),
"ttien" : 1200
}
{
"_id" : ObjectId("60bf577730ef6451158dd342"),
"sohd" : "1235",
"makh" : "k02",
"ngay" : ISODate("2021-05-01T00:00:00Z"),
"ttien" : 2000
}
{
"_id" : ObjectId("60bf577730ef6451158dd343"),
"sohd" : "1236",
"makh" : "k03",
"ngay" : ISODate("2021-05-02T00:00:00Z"),
"ttien" : 2300
}
{
"_id" : ObjectId("60bf577730ef6451158dd344"),
"sohd" : "1237",
"makh" : "k01",
"ngay" : ISODate("2021-05-02T00:00:00Z"),
"ttien" : 2400
}
{
"_id" : ObjectId("60bf577730ef6451158dd345"),
39
"sohd" : "1238",
"makh" : "k03",
"ngay" : ISODate("2021-05-02T00:00:00Z"),
"ttien" : 1500
}
{
"_id" : ObjectId("60bf577730ef6451158dd346"),
"sohd" : "1239",
"makh" : "k05",
"ngay" : ISODate("2021-05-03T00:00:00Z"),
"ttien" : 4800
}
{
"_id" : ObjectId("60bf577730ef6451158dd347"),
"sohd" : "1240",
"makh" : "k04",
"ngay" : ISODate("2021-05-03T00:00:00Z"),
"ttien" : 2500
}
{
"_id" : ObjectId("60bf577730ef6451158dd348"),
"sohd" : "1241",
"makh" : "k02",
"ngay" : ISODate("2021-05-03T00:00:00Z"),
"ttien" : 5000
}
{
"_id" : ObjectId("60bf577730ef6451158dd349"),
"sohd" : "1242",
"makh" : "k01",
40
"ngay" : ISODate("2021-05-04T00:00:00Z"),
"ttien" : 2600
}
{
"_id" : ObjectId("60bf577730ef6451158dd34a"),
"sohd" : "1243",
"makh" : "k05",
"ngay" : ISODate("2021-05-05T00:00:00Z"),
"ttien" : 4100
}
{
"_id" : ObjectId("60bf577730ef6451158dd34b"),
"sohd" : "1243",
"makh" : "k01",
"ngay" : ISODate("2021-05-05T00:00:00Z"),
"ttien" : 3600
}
{
"_id" : ObjectId("60bf577730ef6451158dd34c"),
"sohd" : "1244",
"makh" : "k03",
"ngay" : ISODate("2021-05-06T00:00:00Z"),
"ttien" : 1200
}
{
"_id" : ObjectId("60bf577730ef6451158dd34d"),
"sohd" : "1245",
"makh" : "k01",
"ngay" : ISODate("2021-05-06T00:00:00Z"),
"ttien" : 1400
41
}
‘Map reduce 1 bước: tổng hợp theo makh: k01, tính tổng ttien
> db.BanHang.mapReduce (
…function() {emit(this.makh, this.ttien);},
…function(key, values) {return Array.sum(values)},
…{
…query: {makh: "k01"},
…out: "ketqua2"
…}
…)
{ "result" : "ketqua2", "ok" : 1 }
> db.ketqua2.find()
{ "_id" : "k01", "value" : 11200 }
‘Map reduce 1 bước: tổng hợp theo makh, tính tổng ttien
> db.BanHang.mapReduce(
…function() {emit(this.makh, this.ttien);},
…function(key, values){return Array.sum(values)},
…{
…out : "ketqua3"
…})
{ "result" : "ketqua3", "ok" : 1 }
> db.ketqua3.find()
{ "_id" : "k05", "value" : 8900 }
{ "_id" : "k04", "value" : 2500 }
{ "_id" : "k03", "value" : 5000 }
{ "_id" : "k01", "value" : 11200 }
{ "_id" : "k02", "value" : 7000 }
42
‘Map reduce 1 bước: tổng hợp theo ngay, tính tổng ttien
> db.BanHang.mapReduce(
…function() {emit(this.ngay, this.ttien);},
…function(key, values){return Array.sum(values)},
…{
…out : "ketqua4"
…})
{ "result" : "ketqua4", "ok" : 1 }
> db.ketqua4.find()
{ "_id" : ISODate("2021-05-02T00:00:00Z"), "value" : 6200 }
{ "_id" : ISODate("2021-05-03T00:00:00Z"), "value" : 12300 }
{ "_id" : ISODate("2021-05-04T00:00:00Z"), "value" : 2600 }
{ "_id" : ISODate("2021-05-05T00:00:00Z"), "value" : 7700 }
{ "_id" : ISODate("2021-05-06T00:00:00Z"), "value" : 2600 }
{ "_id" : ISODate("2021-05-01T00:00:00Z"), "value" : 3200 }
‘Map reduce 1 bước: tổng hợp theo makh, tính tổng ttien, sắp xếp theo makh
> db.BanHang.mapReduce(
…function() {emit(this.makh, this.ttien);},
…function(key, values){return Array.sum(values)},
…{
…query: {ngay: {$gt: new Date("2021-05-03")}},
…sort: {makh: 1},
…out : "ketqua5"
…})
{ "result" : "ketqua5", "ok" : 1 }
> db.ketqua5.find()
{ "_id" : "k01", "value" : 7600 }
{ "_id" : "k03", "value" : 1200 }
43
{ "_id" : "k05", "value" : 4100 }
Tham khảo:
https://www.geeksforgeeks.org/mongodb-map-reduce/
https://docs.mongodb.com/manual/core/map-reduce/
https://docs.mongodb.com/manual/reference/method/db.collection.mapReduce/
https://www.tutorialspoint.com/mongodb/mongodb_map_reduce.htm
https://quantrimang.com/map-reduce-trong-mongodb-157785
https://www.geeksforgeeks.org/mongodb-map-reduce/
https://data-flair.training/blogs/mongodb-mapreduce/
// address document
{
patron_id: "joe", // reference to patron document
street: "123 Fake Street",
city: "Faketon",
state: "MA",
zip: "12345"
}
44
Nếu dữ liệu địa chỉ thường xuyên được truy xuất cùng với thông tin tên, thì mô hình dữ liệu
tốt nhất sẽ là nhúng dữ liệu địa chỉ vào dữ liệu khách hàng, như trong tài liệu sau:
{
_id: "joe",
name: "Joe Bookreader",
address: {
street: "123 Fake Street",
city: "Faketon",
state: "MA",
zip: "12345"
}
}
Hiện tại, collection movie chứa một số trường mà ứng dụng không cần thiết hiển thị, chẳng
hạn như thông tin về toàn cảnh và xếp hạng. Thay vì lưu trữ tất cả dữ liệu movie trong một
collection duy nhất, ta có thể chia collection thành hai collection có quan hệ 1 – 1 như sau:
// movie collection
{
"_id": 1,
"title": "The Arrival of a Train",
"year": 1896,
"runtime": 1,
"released": ISODate("1896-01-25"),
"type": "movie",
"directors": [ "Auguste Lumière", "Louis Lumière" ],
"countries": [ "France" ],
"genres": [ "Documentary", "Short" ],
}
Và
// movie_details collection
{
"_id": 156,
"movie_id": 1, // reference to the movie collection
"poster": "http://ia.media-
imdb.com/images/M/MV5BMjEyNDk5MDYzOV5BMl5BanBnXkFtZTgwNjIxMTEwMzE@
._V1_SX300.jpg",
"plot": "A group of people are standing in a straight line along
the platform of a railway station, waiting for a train, which is
seen coming at some distance. When the train stops at the
platform, ...",
"fullplot": "A group of people are standing in a straight line
along the platform of a railway station, waiting for a train,
which is seen coming at some distance. When the train stops at the
platform, the line dissolves. The doors of the railway-cars open,
and people on the platform help passengers to get off.",
"lastupdated": ISODate("2015-08-15T10:06:53"),
"imdb": {
"rating": 7.3,
"votes": 5043,
"id": 12
46
},
"tomatoes": {
"viewer": {
"rating": 3.7,
"numReviews": 59
},
"lastUpdated": ISODate("2020-01-29T00:02:53")
}
}
Vd: Thay vì lưu trữ tất cả các bài đánh giá với sản phẩm, ta có thể chia collection (bộ sưu
tập) thành hai collection: Collection products lưu trữ thông tin về từng sản phẩm, bao gồm
mười đánh giá gần đây nhất về sản phẩm, và collection reviews chứa tất cả các bài đánh giá
của các sán phẩm.
{
"_id": 1,
"name": "Super Widget",
"description": "This is the most useful item in your toolbox.",
"price": { "value": NumberDecimal("119.99"), "currency":
"USD" },
"reviews": [
{
"review_id": 786,
"review_author": "Kristina",
"review_text": "This is indeed an amazing widget.",
"published_date": ISODate("2019-02-18")
}
...
{
"review_id": 776,
"review_author": "Pablo",
"review_text": "Amazing!",
"published_date": ISODate("2019-02-16")
}
]
}
Và collection reviews lưu trữ tất cả các đánh giá. Mỗi bài đánh giá có chứa một tham chiếu
đến collection products mà nó đã được viết.
48
{
"review_id": 786,
"product_id": 1,
"review_author": "Kristina",
"review_text": "This is indeed an amazing widget.",
"published_date": ISODate("2019-02-18")
}
{
"review_id": 785,
"product_id": 1,
"review_author": "Trina",
"review_text": "Nice product. Slow shipping.",
"published_date": ISODate("2019-02-17")
}
...
{
"review_id": 1,
"product_id": 1,
"review_author": "Hans",
"review_text": "Meh, it's okay.",
"published_date": ISODate("2017-12-06")
}
49
> db.Users.find()
{ "_id" : ObjectId("60c34d384b8941d9f23fdc9a"), "userid" : "Ad", "email" :
"admin1@gmail.com", "username" : "admin" }
{ "_id" : ObjectId("60c34d384b8941d9f23fdc9b"), "userid" : "us1", "email" :
"phanthanhlong@gmail.com", "username" : "user 1" }
{ "_id" : ObjectId("60c34d384b8941d9f23fdc9c"), "userid" : "us5", "email" :
"nguyenvanan@gmail.com", "username" : "user 2" }
> db.Userinfo.insertMany([
... {userid: "Ad", phone: "1000000000"},
... {userid: "us1", phone: "1000000001"},
... {userid: "us5", phone: "1000000003"}
... ])
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("60c34e6d4b8941d9f23fdc9d"),
ObjectId("60c34e6d4b8941d9f23fdc9e"),
ObjectId("60c34e6d4b8941d9f23fdc9f")
]
}
> db.Userrole.insertMany([
... {userid: "Ad", role: "Admin"},
... {userid: "us1", role: "Member 1"},
... {userid: "us5", role: "Member 5"}
... ])
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("60c34ef34b8941d9f23fdca0"),
ObjectId("60c34ef34b8941d9f23fdca1"),
ObjectId("60c34ef34b8941d9f23fdca2")
50
]
}
> db.Users.aggregate([
... { $lookup: {
... from: "Userrole",
... localField: "userid",
... foreignField: "userid",
... as: "Users_Role" }
... },
... { $lookup: {
... from: "Users_Info",
... localField: "userid",
... foreignField: "userid",
... as: "Users_Info" }
... },
... ])
{ "_id" : ObjectId("60c34d384b8941d9f23fdc9a"), "userid" : "Ad", "email" :
"admin1@gmail.com", "username" : "admin", "Users_Role" : [ { "_id" :
ObjectId("60c34ef34b8941d9f23fdca0"), "userid" : "Ad", "role" : "Admin" } ],
"Users_Info" : [ ] }
{ "_id" : ObjectId("60c34d384b8941d9f23fdc9b"), "userid" : "us1", "email" :
"phanthanhlong@gmail.com", "username" : "user 1", "Users_Role" : [ { "_id" :
ObjectId("60c34ef34b8941d9f23fdca1"), "userid" : "us1", "role" : "Member 1" } ],
"Users_Info" : [ ] }
{ "_id" : ObjectId("60c34d384b8941d9f23fdc9c"), "userid" : "us5", "email" :
"nguyenvanan@gmail.com", "username" : "user 2", "Users_Role" : [ { "_id" :
ObjectId("60c34ef34b8941d9f23fdca2"), "userid" : "us5", "role" : "Member 5" } ],
"Users_Info" : [ ] }
51