Giới thiệu
Để so sánh giá trị giữa hai trường trong cùng một tài liệu, MongoDB cung cấp toán tử $where cho phép sử dụng biểu thức JavaScript. Tuy nhiên, cách này có hiệu suất kém hơn so với các toán tử truy vấn thông thường.
Ví dụ minh họa
1. Tạo collection với dữ liệu
> db.soSanhTruong.insertOne({"GiaTri1":30,"GiaTri2":40});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9c99ed2d6669774125246e") }
> db.soSanhTruong.insertOne({"GiaTri1":60,"GiaTri2":70});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9c99f62d6669774125246f") }
> db.soSanhTruong.insertOne({"GiaTri1":160,"GiaTri2":190});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9c99ff2d66697741252470") }
> db.soSanhTruong.insertOne({"GiaTri1":200,"GiaTri2":160});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9c9a0b2d66697741252471") }
2. Tìm tài liệu nơi GiaTri1 > GiaTri2
> db.soSanhTruong.find({ $where: "this.GiaTri1 > this.GiaTri2" });
Kết quả:
{ "_id" : ObjectId("5c9c9a0b2d66697741252471"), "GiaTri1" : 200, "GiaTri2" : 160 }
3. Tìm tài liệu nơi GiaTri1 < GiaTri2
> db.soSanhTruong.find({ $where: "this.GiaTri1 < this.GiaTri2" });
Kết quả:
{ "_id" : ObjectId("5c9c99ed2d6669774125246e"), "GiaTri1" : 30, "GiaTri2" : 40 }
{ "_id" : ObjectId("5c9c99f62d6669774125246f"), "GiaTri1" : 60, "GiaTri2" : 70 }
{ "_id" : ObjectId("5c9c99ff2d66697741252470"), "GiaTri1" : 160, "GiaTri2" : 190 }
Các phương án thay thế hiệu quả hơn
Từ MongoDB 3.6+, bạn có thể sử dụng $expr kết hợp với các toán tử aggregation để so sánh trường với hiệu suất tốt hơn:
// Tương đương với $where nhưng nhanh hơn
db.soSanhTruong.find({ $expr: { $gt: ["$GiaTri1", "$GiaTri2"] } });
db.soSanhTruong.find({ $expr: { $lt: ["$GiaTri1", "$GiaTri2"] } });
Lưu ý về hiệu suất
$wherekhông sử dụng index, phải quét toàn bộ collection$exprcó thể tận dụng index trong một số trường hợp- Tránh sử dụng $where trên dataset lớn