Trong chuyện ngoại tình của loài người, thật tệ khi có nhiều mối quan hệ. Tuy nhiên, trong khoa học máy tính, nó là tốt.
Gần đây tôi đã thêm thẻ vào bài viết trên blog. Mối quan hệ thẻ blog này là một mô hình mối quan hệ nhiều người nhiều cổ điển. Tài liệu MongoDB chỉ viết về cách mô hình hóa mối quan hệ một-nhiều. Vì vậy, tôi sẽ chỉ cho bạn cách tôi mô hình hóa mối quan hệ nhiều đến nhiều ở MongoDB, trong đó dữ liệu của trang web này được lưu trữ.
Điều kiện tiên quyết
Tôi cho rằng bạn đã cài đặt MongoDB trên máy tính của mình và có kiến thức cơ bản về NoQuery.
Theo văn bản này, MongoDB của tôi là phiên bản 5.0.4. Tôi tin rằng phiên bản 3.0 trở lên hoạt động tốt với tất cả các lệnh được hiển thị bên dưới.
Nếu bạn chưa cài đặt MongoDB, vui lòng tham khảo Hướng dẫn cài đặt của họ.
Người mẫu
Ý tưởng về mối quan hệ thẻ blog được mô tả như dưới đây:
Các mô hình dưới đây không chính xác là cách cơ sở dữ liệu của tôi được mô hình hóa. Nó chỉ là để cho bạn thấy như một hướng dẫn.
Blog{
id: Integer,
title: String,
tags: Array of Tag ID
}
Tag{
id: Integer,
name: String,
}
Tôi đã thêm ID trường để người đọc có thể sao chép, dán và chạy các truy vấn tương tự. Nhưng trong ứng dụng thực tế, ObjectID _ID được gán cho mọi tài liệu sẽ thực hiện trên thực tế nó được ưa thích.
Bình thường hóa V.S. Nhúng
Trong mô hình ở trên, tôi đã áp dụng mô hình dữ liệu được chuẩn hóa, còn được gọi là mô hình tham chiếu. Trong mô hình dữ liệu được chuẩn hóa, các tài liệu lưu trữ tham chiếu đến các tài liệu khác, được sử dụng để liên kết hai tài liệu. Thông thường đối tượng của tài liệu được sử dụng làm tài liệu tham khảo.
Nguồn: MongoDBCách khác của mô hình hóa là mô hình dữ liệu nhúng. Trong mô hình này, các mối quan hệ của dữ liệu được lưu trữ dưới dạng tài liệu phụ bên trong một tài liệu duy nhất.
Cách khác của mô hình hóa là mô hình dữ liệu nhúng. Trong mô hình này, các mối quan hệ của dữ liệu được lưu trữ dưới dạng tài liệu phụ bên trong một tài liệu duy nhất.
Nói chung, trong các mối quan hệ một-nhiều hoặc nhiều đến nhiều, mô hình dữ liệu được chuẩn hóa là thích hợp hơn vì nó có thể lưu lượng dữ liệu và thay đổi trên tài liệu được tham chiếu cập nhật tất cả các tài liệu tham khảo liên quan đến dữ liệu. Ngay cả đối với mối quan hệ một-một trong đó liên kết giữa hai tài liệu rất yếu hoặc rất tinh tế như thông tin thẻ tín dụng cho người dùng, bạn có thể sử dụng mô hình dữ liệu được chuẩn hóa.
Dữ liệu hạt giống
% brew services start mongodb-community # on version 5
% mongosh
Ví dụ, tôi sẽ sử dụng cơ sở dữ liệu có tên M2M, là viết tắt của nhiều-nhiều và hai blog và thẻ bộ sưu tập. Để lưu trữ dữ liệu hạt giống vào cơ sở dữ liệu, hãy khởi động MongoDB của bạn và đăng nhập vào vỏ của nó:
> use m2m
> db.tags.insertMany[[
{id: 0, name: 'Node.js'},
{id: 1, name: 'MongoDB'},
{id: 2, name: 'React.js'}
]]
> db.blogs.insertMany[[
{id: 0, title: 'Mongoose', tags: [0, 1]},
{id: 1, title: 'GraphQL', tags: [1, 2]},
{id: 2, title: 'ReactDOMServer', tags: [0, 2]}
]]
Và tạo ba tài liệu cho mỗi bộ sưu tập với Chèn chèn []:
> db.tags.find[]
// Output
[
{_id: ObjectId["62…bd"], id: 0, name: 'Node.js'},
{_id: ObjectId["62…be"], id: 1, name: 'MongoDB'},
{_id: ObjectId["62…bf"], id: 2, name: 'React.js'}
]
> db.blogs.find[]
// Output
[
{_id: ObjectId["62…c0"], id: 0, title: 'Mongoose', tags: [0, 1]},
{_id: ObjectId["62…c1"], id: 1, title: 'GraphQL', tags: [1, 2]},
{_id: ObjectId["62…c2"], id: 2, title: 'ReactDOMServer', tags: [0, 2]}
]
Vui lòng đảm bảo rằng những dữ liệu đó được lưu trữ với db.collection.find []:
Từ giờ trở đi trong bài đăng này, tôi sẽ loại bỏ trường _id khỏi các đầu ra.
Truy vấn
Để tính toán các tài liệu thông qua nhiều quy trình, chúng tôi sử dụng các hoạt động tổng hợp trong MongoDB.
- Chúng tôi đã sử dụng db.collection.find [] ở trên và hàm này chấp nhận ba phương thức truy vấn, trình chiếu và con trỏ đối số.: determines the filter which documents are to be returned.
- Truy vấn: Xác định bộ lọc mà tài liệu sẽ được trả về.: determines which fields are returned in the matching documents.
- Dự đoán: Xác định các trường nào được trả về trong các tài liệu phù hợp.: determines optional computation such as sort, limit, skip.
Phương pháp con trỏ: Xác định tính toán tùy chọn như sắp xếp, giới hạn, bỏ qua.
> db.blogs.find[{tags: 1}, {_id: 0}, {sort: {id: -1}, skip: 1, limit: 1}];
// Output
[
{id: 0, title: 'Mongoose', tags: [0, 1]}
]
Vui lòng thử một truy vấn:
> db.blogs.aggregate[[
{$match: {tags: 1}},
{$project: {_id: 0}},
{$sort: {id: -1}},
{$skip: 1},
{$limit: 1}
]]
// Output
[
{id: 0, title: 'Mongoose', tags: [0, 1]}
]
Đây là một truy vấn đơn giản, vì vậy nó không phải là một vấn đề. Nhưng khi truy vấn trở nên phức tạp, nó sẽ. Và một số truy vấn, giống như kết nối dữ liệu bài đăng trên blog với dữ liệu thẻ là không thể. Phương thức Find [] ở trên có thể được viết lại bằng db.collection.aggregate [] như:
Tham gia với $ Tra cứu
Trong cơ sở dữ liệu quan hệ SQL, chúng tôi sử dụng tham gia để liên quan đến hai bảng. Trong MongoDB, chúng tôi sử dụng $ Tra cứu để có được kết quả tương tự.
> db.blogs.aggregate[[
{$lookup: {from: 'tags', localField: 'tags', foreignField: 'id', as: 'tags'}},
]]
// Output
[
{
id: 0,
title: 'Mongoose',
tags: [{id: 0, name: 'Node.js'}, {id: 1, name: 'MongoDB'}]
},
{
id: 1,
title: 'GraphQL',
tags: [{id: 1, name: 'MongoDB'}, {id: 2, name: 'React.js'}]
},
{
id: 2,
title: 'ReactDOMServer',
tags: [{id: 0, name: 'Node.js'}, {id: 2, name: 'React.js'}]
}
]
Bây giờ, hãy để thử một lần tra cứu $ đơn giản:
ID của các thẻ trong tài liệu blog được thay thế bằng các tài liệu thẻ.
Việc tra cứu $ ở trên là một chút khó khăn. Khi Localfield là một mảng, bạn có thể tham gia các tài liệu chống lại trường nước ngoài vô hướng. Để biết chi tiết, vui lòng tham khảo sử dụng $ Tra cứu với một mảng.
Lọc theo thẻ
> db.blogs.aggregate[[
{$match: {tags: 0}},
{$lookup: {from: 'tags', localField: 'tags', foreignField: 'id', as: 'tags'}}
]]
// Output
[
{
id: 0,
title: 'Mongoose',
tags: [{id: 0, name: 'Node.js'}, {id: 1, name: 'MongoDB'}]
},
{
id: 2,
title: 'ReactDOMServer',
tags: [{id: 0, name: 'Node.js'}, {id: 2, name: 'React.js'}]
}
]
OK, chúng tôi hiểu cơ bản của $ tra cứu. Tiếp theo, chúng tôi muốn chỉ tìm thấy các bài đăng trên blog được gắn thẻ Node.js.
Xem rằng chúng tôi chỉ nhận được các bài đăng trên blog được gắn thẻ Node.js [ID: 0] và bài đăng trên blog GraphQL được lọc ra.
$ Tra cứu đường ống
Bây giờ hãy tưởng tượng một tình huống mà bạn không muốn cho mọi người thấy một số thẻ nhất định, hiện tại nó hiện đang được thử nghiệm. Hãy để nói rằng bạn là người mới để React.js. Mặc dù bạn gắn thẻ các bài viết bằng thẻ đó, nhưng bạn không muốn hiển thị nó trong kết quả truy vấn. Để làm điều này, chúng tôi vượt qua đường ống ở giai đoạn tra cứu $.
> db.blogs.aggregate[[
{$lookup: {
from: 'tags',
localField: 'tags',
foreignField: 'id',
as: 'tags',
pipeline: [
{$match: {name: {$ne: 'React.js'}}}
]
}}
]]
// Output
[
{
id: 0,
title: 'Mongoose',
tags: [{id: 0, name: 'Node.js'}, {id: 1, name: 'MongoDB'}]
},
{
id: 1,
title: 'GraphQL',
tags: [{id: 1, name: 'MongoDB'}]
},
{
id: 2,
title: 'ReactDOMServer',
tags: [{id: 0, name: 'Node.js'}]
}
]
Truy vấn dưới đây là cách bạn làm điều đó:
React.js được xóa khỏi danh sách thẻ được nối với các tài liệu.
Đếm bài đăng được gắn thẻ
Ví dụ tuyệt vời mà bạn muốn hiển thị số lượng bài đăng được gắn thẻ từ khóa nhất định là thẻ của trang web này.
{
id: Integer,
name: String,
}
0Sự kết luận
Để tạo mối quan hệ nhiều thứ trong cơ sở dữ liệu quan hệ, chúng tôi phải tạo một bảng trung gian như blog_TAG lưu trữ ID blog và ID thẻ trong các hàng. Trong MongoDB, là một cơ sở dữ liệu định hướng tài liệu, không cần thiết.
Bạn có thể có bất kỳ trường hợp nào mà chúng tôi đã giành được các truy vấn thực hiện ở MongoDB mà chúng tôi từng làm trong MySQL không? Thành thật mà nói, tôi không thể trả lời câu hỏi đó. "Cái nào tốt hơn, MongoDB hay MySQL?" Tôi cũng không thể trả lời câu hỏi đó.
Chúng tôi ước rằng có thể có một giải pháp một trong tất cả, nhưng mọi thứ đều đánh đổi trong phát triển và kỹ thuật. Giải pháp tốt nhất phụ thuộc vào cách chúng ta mô hình hóa dữ liệu, nói cách khác, vào chúng ta, thay vì vào công nghệ.
Các truy vấn mẫu mực được hiển thị ở trên, và mô hình nhiều đến nhiều mà tôi đã áp dụng, chỉ là một cách tiếp cận. Bạn có thể nghĩ ra ý tưởng tốt hơn.
Và để có được hầu hết MongoDB, chúng ta sẽ quen với nó, thay vì hiểu nó.
Tài nguyên
- MongoDB
- Mô hình mối quan hệ một-nhiều nhiều với tài liệu tham khảo tài liệu
- Hoạt động tổng hợp
- MongoDB Mối quan hệ nhiều đến nhiều với các ví dụ Mongoose