Trong MongoDB có hai cách thể hiện quan hệ: nhúng dữ liệu con ngay trong document (embedding) hay tách ra và tham chiếu qua ObjectId (referencing).
Embedding (lồng vào): dùng khi dữ liệu hay được đọc cùng nhau, quan hệ 1:1 hoặc 1:ít, ít thay đổi, con không cần tồn tại độc lập. Ưu: chỉ một query, không cần join.
Referencing (tham chiếu): dùng khi dữ liệu lớn, quan hệ nhiều-nhiều, hoặc con được đọc/sửa độc lập. Nhược: cần $lookup (kiểu LEFT JOIN) hoặc join ở tầng app — tốn thêm round-trip.
Đánh đổi cốt lõi: nhúng làm đọc nhanh nhưng ghi tốn (nhân bản dữ liệu, sửa phải sửa nhiều chỗ).
Lưu ý: mỗi document tối đa 16MB — nhúng quá tay sẽ chạm trần. Vài pattern hữu ích: bucket (gom time-series theo giờ thay vì mỗi lần đo một document) để giảm số document; outlier (tách riêng các trường hợp ngoại lệ khi 90% nhỏ nhưng 10% cực lớn, vd bài của celebrity triệu like). Khi $lookup, nhớ index cột nối.
In MongoDB there are two ways to model a relationship: embed the child data inside the document (embedding) or split it out and point to it via ObjectId (referencing).
Embedding (nesting): use when data is usually read together, the relationship is 1:1 or 1:few, it changes rarely, and the child needn't exist independently. Pro: a single query, no joins.
Referencing: use when data is large, the relationship is many-to-many, or the child is read/updated independently. Con: needs $lookup (LEFT-JOIN-style) or an app-side join — extra round-trips.
Core trade-off: embedding makes reads fast but writes costly (data is duplicated, so an update touches many places).
Note: each document maxes out at 16MB — over-embedding hits that ceiling. A couple of useful patterns: bucket (group time-series by hour instead of one document per reading) to cut document count; outlier (handle exceptions separately when 90% are small but 10% are huge, e.g. a celebrity post with millions of likes). When using $lookup, index the join field.