Có một số cách để làm điều này.
Đầu tiên là với Toán tử Tổng hợp Ngày tháng, cho phép bạn phân tích các giá trị "ngày tháng" trong tài liệu. Cụ thể cho "nhóm" làm mục đích chính:
db.collection.aggregate([
{ "$group": {
"_id": {
"year": { "$year": "$created_at" },
"dayOfYear": { "$dayOfYear": "$created_at" },
"hour": { "$hour": "$created_at" },
"interval": {
"$subtract": [
{ "$minute": "$created_at" },
{ "$mod": [{ "$minute": "$created_at"}, 15] }
]
}
}},
"count": { "$sum": 1 }
}}
])
Cách thứ hai là sử dụng một mẹo nhỏ về thời điểm một đối tượng ngày bị trừ (hoặc phép toán trực tiếp khác) khỏi đối tượng ngày khác, khi đó kết quả là một giá trị số đại diện cho dấu thời gian kỷ nguyên mili giây giữa hai đối tượng. Vì vậy, chỉ cần sử dụng ngày kỷ nguyên, bạn sẽ có được đại diện cho phần nghìn giây của kỷ nguyên. Sau đó, sử dụng toán học ngày cho khoảng thời gian:
db.collection.aggregate([
{ "$group": {
"_id": {
"$subtract": [
{ "$subtract": [ "$created_at", new Date("1970-01-01") ] },
{ "$mod": [
{ "$subtract": [ "$created_at", new Date("1970-01-01") ] },
1000 * 60 * 15
]}
]
},
"count": { "$sum": 1 }
}}
])
Vì vậy, nó phụ thuộc vào loại định dạng đầu ra bạn muốn cho khoảng thời gian nhóm. Về cơ bản, cả hai đều đại diện cho cùng một thứ và có đủ dữ liệu để xây dựng lại dưới dạng đối tượng "ngày tháng" trong mã của bạn.
Bạn có thể đặt bất kỳ thứ gì khác mà bạn muốn vào phần "toán tử nhóm" sau _id
nhóm . Tôi chỉ đang sử dụng ví dụ "đếm" cơ bản thay cho bất kỳ tuyên bố thực tế nào của bạn về những gì bạn thực sự muốn làm.
MongoDB 4.x trở lên
Đã có một số bổ sung cho Toán tử tổng hợp ngày kể từ bản viết gốc, nhưng từ MongoDB 4.0 sẽ có "thực tế đúc các kiểu" trái ngược với các thủ thuật toán học cơ bản được thực hiện ở đây với chuyển đổi Ngày của BSON.
Ví dụ:chúng ta có thể sử dụng $toLong
và $toDate
với tư cách là những người trợ giúp mới tại đây:
db.collection.aggregate([
{ "$group": {
"_id": {
"$toDate": {
"$subtract": [
{ "$toLong": "$created_at" },
{ "$mod": [ { "$toLong": "$created_at" }, 1000 * 60 * 15 ] }
]
}
},
"count": { "$sum": 1 }
}}
])
Điều đó ngắn hơn một chút và không yêu cầu xác định Ngày BSON bên ngoài cho giá trị "epoch" như một hằng số trong việc xác định đường dẫn, vì vậy nó khá nhất quán cho tất cả các triển khai ngôn ngữ.
Đó chỉ là hai trong số các phương thức "trợ giúp" để chuyển đổi kiểu, tất cả đều liên quan đến $convert
, là một dạng triển khai "dài hơn" cho phép xử lý tùy chỉnh trên null
hoặc lỗi trong chuyển đổi.
Thậm chí có thể với việc truyền như vậy để có được Date
thông tin từ ObjectId
của khóa chính, vì đây sẽ là nguồn đáng tin cậy về ngày "tạo":
db.collection.aggregate([
{ "$group": {
"_id": {
"$toDate": {
"$subtract": [
{ "$toLong": { "$toDate": "$_id" } },
{ "$mod": [ { "$toLong": { "$toDate": "$_id" } }, 1000 * 60 * 15 ] }
]
}
},
"count": { "$sum": 1 }
}}
])
Vì vậy, "kiểu truyền" với kiểu chuyển đổi này có thể là một công cụ khá mạnh mẽ.
Cảnh báo -
ObjectId
giá trị được giới hạn ở độ chính xác đến giây chỉ cho giá trị thời gian nội bộ tạo nên một phần dữ liệu của chúng cho phép$toDate
sự chuyển đổi. "Thời gian" được chèn thực tế có lẽ phụ thuộc nhiều nhất vào trình điều khiển được sử dụng. Ở đâu độ chính xác là bắt buộc, bạn vẫn nên sử dụng trường Ngày BSON rời rạc thay vì dựa vàoObjectId
giá trị.