Trường _id mặc định của MongoDB là **ObjectId**, chứa timestamp tạo tài liệu (4 byte đầu). Do đó, sắp xếp theo _id tương đương với sắp xếp theo **thời gian tạo** (creation time). Đây là cách hiệu quả nhất để lấy bản ghi mới nhất/cũ nhất mà không cần trường createdAt riêng.
1. Tạo bộ sưu tập
> db.demo403.insertOne({ "Name": "Chris" });
> db.demo403.insertOne({ "Name": "David" });
> db.demo403.insertOne({ "Name": "Bob" });
> db.demo403.insertOne({ "Name": "Adam" });
2. Xem dữ liệu (thứ tự chèn = thứ tự _id tăng dần)
> db.demo403.find();
Kết quả: Chris, David, Bob, Adam (theo thứ tự insert).
3. Sắp xếp giảm dần (_id mới nhất trước)
> db.demo403.find().sort({ _id: -1 });
4. Kết quả
{ "_id": ObjectId("5e6f89b8..."), "Name": "Adam" } // Mới nhất
{ "_id": ObjectId("5e6f89b5..."), "Name": "Bob" }
{ "_id": ObjectId("5e6f89b2..."), "Name": "David" }
{ "_id": ObjectId("5e6f89b0..."), "Name": "Chris" } // Cũ nhất
Giải thích: ObjectId hex string càng lớn = timestamp càng mới. sort({ _id: -1 }) = mới nhất trước. sort({ _id: 1 }) = cũ nhất trước.
Ứng dụng thực tế:
- Lấy 10 bản ghi mới nhất:
find().sort({ _id: -1 }).limit(10). - Phân trang keyset (hiệu quả hơn skip):
find({ _id: { $lt: lastSeenId } }).sort({ _id: -1 }).limit(10). - Không cần index thêm (index _id mặc định luôn có).
Lưu ý: ObjectId chỉ đảm bảo tăng dần theo giây. Nếu insert hàng nghìn doc/giây, thứ tự trong cùng giây có thể không chính xác tuyệt đối. Cần trường createdAt nếu yêu cầu chính xác cao.