Node.js - MongoDB Join

MongoDB là một cơ sở dữ liệu NoSQL, và nó không hỗ trợ các thao tác JOIN như trong các cơ sở dữ liệu quan hệ như MySQL. Tuy nhiên, một chức năng tương tự có thể được đạt được bằng cách gọi phương thức aggregate() của đối tượng Collection, và giai đoạn $lookup.

$aggregate() function

Hàm này thực hiện một phép nối ngoài trái với một bộ sưu tập khác trong cùng một cơ sở dữ liệu để lọc các tài liệu từ bộ sưu tập "được nối" để xử lý.

$lookup: Thực hiện một phép nối bên trái với một bộ sưu tập trong cùng một cơ sở dữ liệu để lọc các tài liệu từ bộ sưu tập "được nối" để xử lý. Giai đoạn $lookup thêm một trường mảng mới vào mỗi tài liệu đầu vào. Trường mảng mới này chứa các tài liệu phù hợp từ bộ sưu tập "được nối".

Để thực hiện một phép so sánh bằng giữa một trường từ các tài liệu đầu vào với một trường từ các tài liệu của bộ sưu tập "được kết hợp", giai đoạn $lookup có cú pháp như sau −

{
   $lookup:
      {
         from: <collection to join>,
         localField: <field from the input documents>,
         foreignField: <field from the documents of the "from" collection>,
         as: <output array field>
      }
}

Các tham số trong giai đoạn $lookup như sau −

Sr.No Parameter & Description
1 from Specifies the collection in the same database to perform the join with. from is optional, you can use a $documents stage in a $lookup stage instead. For an example, see Use a $documents Stage in a $lookup Stage.
2 localField Specifies the field from the documents input to the $lookup stage. $lookup performs an equality match on the localField to the foreignField from the documents of the from collection.
3 foreignField Specifies the field from the documents in the from collection.
4 As Specifies the name of the new array field to add to the input documents. The new array field contains the matching documents from the from collection.

Phép toán $lookup tương ứng với truy vấn SQL sau −

SELECT *, <output array field>
FROM collection
WHERE <output array field> IN (
   SELECT *
   FROM <collection to join>
   WHERE <foreignField> = <collection.localField>
);

Example

Để minh họa thao tác JOIN trong MongoDB, hãy tạo hai Collection - inventory và orders.

The inventory Collection

( [
   { prodId: 100, price: 20, quantity: 125 },
   { prodId: 101, price: 10, quantity: 234 },
   { prodId: 102, price: 15, quantity: 432 },
   { prodId: 103, price: 17, quantity: 320 }
] )

The orders collection

( [
   { orderId: 201, custid: 301, prodId: 100, numPurchased: 20 },
   { orderId: 202, custid: 302, prodId: 101, numPurchased: 10 },
   { orderId: 203, custid: 303, prodId: 102, numPurchased: 5 },
   { orderId: 204, custid: 303, prodId: 103, numPurchased: 15 },
   { orderId: 205, custid: 303, prodId: 103, numPurchased: 20 },
   { orderId: 206, custid: 302, prodId: 102, numPurchased: 1 },
   { orderId: 207, custid: 302, prodId: 101, numPurchased: 5 },
   { orderId: 208, custid: 301, prodId: 100, numPurchased: 10 },
   { orderId: 209, custid: 303, prodId: 103, numPurchased: 30 }
] )

Đoạn mã sau gọi phương thức aggregate() trên đối tượng Collection và giai đoạn $lookup.

const {MongoClient} = require('mongodb');

async function main(){

   const uri = "mongodb://localhost:27017/";
   const client = new MongoClient(uri);

   try {
      await client.connect();
      await joindocs(client, "mydb", "orders", "inventory");
   } finally {
      await client.close();
   }
}

main().catch(console.error);

async function joindocs(client, dbname, col1, col2){
   const result = await client.db(dbname).collection('orders').aggregate([
   { $lookup:
      {
         from: 'inventory',
         localField: 'prodId',
         foreignField: 'prodId',
         as: 'orderdetails'
      }
   }
   ]).toArray();
   result.forEach(element => {
      console.log(JSON.stringify(element));
   });
}

Giai đoạn $lookup cho phép bạn chỉ định bộ sưu tập nào bạn muốn kết hợp với bộ sưu tập hiện tại, và các trường nào sẽ được khớp.

Output

{"_id":"658c4b14943e7a1349678bf3","orderId":201,"custid":301,"prodId":100,"numPurchased":20,"orderdetails":[{"_id":"658c4aff943e7a1349678bef","prodId":100,"price":20,"quantity":125}]}
{"_id":"658c4b14943e7a1349678bf4","orderId":202,"custid":302,"prodId":101,"numPurchased":10,"orderdetails":[{"_id":"658c4aff943e7a1349678bf0","prodId":101,"price":10,"quantity":234}]}
{"_id":"658c4b14943e7a1349678bf5","orderId":203,"custid":303,"prodId":102,"numPurchased":5,"orderdetails":[{"_id":"658c4aff943e7a1349678bf1","prodId":102,"price":15,"quantity":432}]}
{"_id":"658c4b14943e7a1349678bf6","orderId":204,"custid":303,"prodId":103,"numPurchased":15,"orderdetails":[{"_id":"658c4aff943e7a1349678bf2","prodId":103,"price":17,"quantity":320}]}
{"_id":"658c4b14943e7a1349678bf7","orderId":205,"custid":303,"prodId":103,"numPurchased":20,"orderdetails":[{"_id":"658c4aff943e7a1349678bf2","prodId":103,"price":17,"quantity":320}]}
{"_id":"658c4b14943e7a1349678bf8","orderId":206,"custid":302,"prodId":102,"numPurchased":1,"orderdetails":[{"_id":"658c4aff943e7a1349678bf1","prodId":102,"price":15,"quantity":432}]}
{"_id":"658c4b14943e7a1349678bf9","orderId":207,"custid":302,"prodId":101,"numPurchased":5,"orderdetails":[{"_id":"658c4aff943e7a1349678bf0","prodId":101,"price":10,"quantity":234}]}
{"_id":"658c4b14943e7a1349678bfa","orderId":208,"custid":301,"prodId":100,"numPurchased":10,"orderdetails":[{"_id":"658c4aff943e7a1349678bef","prodId":100,"price":20,"quantity":125}]}
{"_id":"658c4b14943e7a1349678bfb","orderId":209,"custid":303,"prodId":103,"numPurchased":30,"orderdetails":[{"_id":"658c4aff943e7a1349678bf2","prodId":103,"price":17,"quantity":320}]}