Nếu bạn đã quen với SQL, bạn có thể biết về UNION
mệnh đề, nối kết quả của hai truy vấn thành một tập kết quả duy nhất. Đặc biệt, UNION ALL
bao gồm các bản sao.
Trong MongoDB, chúng ta có thể sử dụng $unionWith
giai đoạn đường ống tổng hợp để đạt được hiệu quả tương tự như UNION ALL
sản xuất. $unionWith
stage thực hiện sự kết hợp của hai tập hợp - nó kết hợp các kết quả đường ống từ hai tập hợp thành một tập kết quả duy nhất. Và nó bao gồm các bản sao.
Ví dụ
Giả sử chúng ta tạo hai bộ sưu tập; một con được gọi là cats
và một cái khác được gọi là dogs
. Và chúng tôi chèn các tài liệu sau vào chúng:
db.cats.insertMany([
{ _id: 1, name: "Fluffy", type: "Cat", weight: 5 },
{ _id: 2, name: "Scratch", type: "Cat", weight: 3 },
{ _id: 3, name: "Meow", type: "Cat", weight: 7 }
])
db.dogs.insertMany([
{ _id: 1, name: "Wag", type: "Dog", weight: 20 },
{ _id: 2, name: "Bark", type: "Dog", weight: 10 },
{ _id: 3, name: "Fluffy", type: "Dog", weight: 40 }
])
Bây giờ chúng tôi có thể chạy truy vấn đối với các bộ sưu tập đó và sử dụng $unionWith
giai đoạn để kết hợp các kết quả của từng truy vấn.
Ví dụ:
db.cats.aggregate( [
{ $set: { _id: "$_id" } },
{ $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "$_id" } } ] } },
{ $sort: { type: 1, weight: -1, name: 1 } }
] )
Kết quả:
{"_id":3, "name":"Meo meo", "type":"Cat", "weight":7} {"_id":1, "name":"Fluffy", "type" :"Cat", "weight":5} {"_id":2, "name":"Scratch", "type":"Cat", "weight":3} {"_id":3, "name" :"Fluffy", "type":"Dog", "weight":40} {"_id":1, "name":"Wag", "type":"Dog", "weight":20} {" _id ":2," name ":" Bark "," type ":" Dog "," weight ":10}
Trong ví dụ này, mỗi tài liệu có một trường loại với cat
hoặc dogs
và do đó, khá rõ ràng là tài liệu nào đến từ bộ sưu tập nào.
Nhưng nếu các tài liệu không có trường loại, thì sẽ khó hơn để tìm ra nơi một bộ sưu tập kết thúc và một bộ sưu tập khác bắt đầu. Trong trường hợp này, chúng ta có thể sử dụng một chuỗi ký tự tại $set
giai đoạn đại diện cho tên bộ sưu tập.
Ví dụ:
db.cats.aggregate( [
{ $set: { _id: "cat" } },
{ $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "dog" } } ] } },
{ $sort: { type: 1, weight: -1, name: 1 } }
] )
Kết quả:
{"_id":"cat", "name":"Meow", "type":"Cat", "weight":7} {"_id":"cat", "name":"Fluffy" , "type":"Cat", "weight":5} {"_id":"cat", "name":"Scratch", "type":"Cat", "weight":3} {"_id" :"dog", "name":"Fluffy", "type":"Dog", "weight":40} {"_id":"dog", "name":"Wag", "type":"Dog "," weight ":20} {" _id ":" dog "," name ":" Bark "," type ":" Dog "," weight ":10}
Sắp xếp giữa các bộ sưu tập
Trong các ví dụ trước, mèo và chó được sắp xếp theo cách tách chúng thành hai nhóm riêng biệt; mèo trước, sau đó đến chó. Điều này xảy ra chủ yếu là do chúng tôi sắp xếp theo loại type
trường đầu tiên.
Nhưng chúng tôi có thể sắp xếp nó trên bất kỳ trường nào khác, điều này có thể dẫn đến việc kết hợp mèo và chó.
Ví dụ:
db.cats.aggregate( [
{ $set: { _id: "cat" } },
{ $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "dog" } } ] } },
{ $sort: { name: 1 } }
] )
Kết quả:
{"_id":"dog", "name":"Bark", "type":"Dog", "weight":10} {"_id":"cat", "name":"Fluffy" , "type":"Cat", "weight":5} {"_id":"dog", "name":"Fluffy", "type":"Dog", "weight":40} {"_id" :"cat", "name":"Meo meo", "type":"Cat", "weight":7} {"_id":"cat", "name":"Scratch", "type":"Cat "," weight ":3} {" _id ":" dog "," name ":" Wag "," type ":" Dog "," weight ":20}
Phép chiếu
Bạn có thể sử dụng $project
giai đoạn để chỉ định trường nào sẽ được chuyển sang giai đoạn tiếp theo trong đường dẫn. Ví dụ:do đó, bạn có thể giảm số lượng trường được trả về bởi truy vấn.
Ví dụ:
db.cats.aggregate( [
{ $project: { name: 1, _id: 0 } },
{ $unionWith: { coll: "dogs", pipeline: [ { $project: { name: 1, _id: 0 } } ]} }
] )
Kết quả:
{"name":"Fluffy"} {"name":"Scratch"} {"name":"Meow"} {"name":"Wag"} {"name":"Bark"} {" tên ":" Fluffy "}
Xóa các bản sao
Bạn có thể sử dụng $group
để loại bỏ các bản sao thừa khỏi kết quả.
Ví dụ:truy vấn trước đó trả về hai vật nuôi có tên là Fluffy. Chúng tôi có thể thêm một $group
chuyển sang truy vấn đó để loại bỏ trùng lặp dư thừa, để chỉ một Fluffy được trả về.
db.cats.aggregate( [
{ $project: { name: 1, _id: 0 } },
{ $unionWith: { coll: "dogs", pipeline: [ { $project: { name: 1, _id: 0 } } ]} },
{ $group: { _id: "$name" } }
] )
Kết quả:
{"_id":"Meow"} {"_id":"Bark"} {"_id":"Scratch"} {"_id":"Wag"} {"_id":"Fluffy"}Lần này, chỉ một Fluffy được trả lại.
Các cột không phù hợp
Một trong những lợi thế mà MongoDB’s
$unionWith
có trênUNION ALL
của SQL là nó có thể được sử dụng với các cột không khớp.
UNION
trong SQL mệnh đề yêu cầu rằng:
- Cả hai truy vấn đều trả về cùng một số cột
- Các cột theo cùng một thứ tự
- Các cột phù hợp phải thuộc loại dữ liệu tương thích
MongoDB $unionWith
giai đoạn không áp đặt những giới hạn này.
Do đó, chúng tôi có thể sử dụng $unionWith
để làm điều gì đó như sau:
db.cats.aggregate( [
{ $set: { _id: "$_id" } },
{ $unionWith: { coll: "employees", pipeline: [ { $set: { _id: "$_id" } } ] } },
{ $sort: { type: 1, salary: -1 } }
] )
Kết quả:
{"_id":2, "name":"Sarah", "lương":128000} {"_id":5, "name":"Beck", "lương":82000} {"_id":4, "name":"Chris", "Lương":45000} {"_id":3, "name":"Fritz", "lương":25000} {"_id":1, "name":"Fluffy "," type ":" Cat "," weight ":5} {" _id ":2," name ":" Scratch "," type ":" Cat "," weight ":3} {" _id ":3, "name":"Meo meo", "type":"Cat", "weight":7}
Trong trường hợp này, chúng tôi đã kết hợp với cats
bộ sưu tập với employees
thu thập. employees
bộ sưu tập không có các trường giống như cats
bộ sưu tập, nhưng điều đó vẫn ổn - nó vẫn hoạt động.