Dapatkan item terakhir yang dimasukkan per hari

Apakah ada fitur di mongodb yang bisa saya gunakan untuk mendapatkan item terakhir yang dimasukkan per hari? Saya memiliki koleksi di mana saya perlu memasukkan item terakhir per hari, datanya dikelompokkan berdasarkan jam seperti pada struktur di bawah ini.

{
   timestamp: 2017-05-04T09:00:00.000+0000,
   data: {}
},
{
   timestamp: 2017-05-04T10:00:00.000+0000,
   data: {}
}

Saya berpikir untuk menggunakan proyeksi tetapi saya tidak yakin bagaimana saya bisa melakukan ini.

Sunting: Selain itu, karena mongodb menyimpan data dalam UTC, saya juga ingin memperhitungkan offsetnya.


person Bazinga777    schedule 06.06.2017    source sumber
comment
pertama, urutkan data berdasarkan stempel waktu (dari terlama ke terbaru). Kemudian, kelompokkan dokumen berdasarkan hari (dalam tahapan $group ) dan pertahankan data terakhir dengan $last   -  person felix    schedule 06.06.2017


Jawaban (1)


Anda dapat $sort dan menggunakan $last untuk item tersebut, dengan membulatkan kunci pengelompokan ke setiap hari:

db.collection.aggregate([
  { "$sort": { "timestamp": 1 } },
  { "$group": {
     "_id": {
       "$add": [
         { "$subtract": [
           { "$subtract": [ "$timestamp", new Date(0) ] },
           { "$mod": [
             { "$subtract": [ "$timestamp", new Date(0) ] },
             1000 * 60 * 60 * 24
           ]}
         ]},
         new Date(0)
       ]
     },
     "lastDoc": { "$last": "$$ROOT" }
  }}
])

Jadi pengurutan membuat segala sesuatunya tampak berurutan, dan kemudian pengelompokan _id dibulatkan untuk setiap hari berdasarkan tanggal matematika tertentu. Anda mengurangi tanggal zaman dari tanggal saat ini untuk menjadikannya angka. Gunakan modulus untuk membulatkan menjadi satu hari, lalu tambahkan tanggal zaman ke angka tersebut untuk menghasilkan Date.

Jadi dengan menghitungnya, kita mendapatkan nilai stempel waktu dari tanggal dengan baris $subract. Kami melakukan ini beberapa kali:

{ "$subtract": [ "$timestamp", new Date(0) ] }

// Is roughly internally like
ISODate("2017-06-06T10:44:37.627Z") - ISODate("1970-01-01T00:00:00Z")
1496745877627

Lalu ada modulo dengan $mod yang bila diterapkan pada nilai numerik akan mengembalikan selisihnya. 1000 milidetik * 60 detik * 60 * menit * 24 jam memberikan argumen lain:

 { "$mod": [
   { "$subtract": [ "$timestamp", new Date(0) ] },
   1000 * 60 * 60 * 24
 ]}

 // Equivalent to 
 1496745877627 % (1000 * 60 * 60 * 24)
 38677627

Lalu ada pembungkus $subtract dari kedua angka tersebut:

 { "$subtract": [
   { "$subtract": [ "$timestamp", new Date(0) ] },
   { "$mod": [
     { "$subtract": [ "$timestamp", new Date(0) ] },
     1000 * 60 * 60 * 24
   ]}
 ]}

 // Subtract "difference" of the modulo to a day
 // from the milliseconds value of the current date
 1496745877627 - 38677627

 1496707200000

Kemudian tambahkan kembali nilai tanggal zaman untuk membuat tanggal yang dibulatkan ke hari ini, yang pada pipa agregasi pada dasarnya terlihat seperti memberikan nilai milidetik ke konstruktor:

new Date(1496707200000)
ISODate("2017-06-06T00:00:00Z")

Yang mengambil nilai stempel waktu dan mengurangi selisih pembagi dari "satu hari" dan berakhir pada waktu di "awal hari".

Cukup gunakan $$ROOT di sini untuk mewakili keseluruhan dokumen. Namun jalur dokumen apa pun yang disediakan ke $last di sini akan memberikan hasilnya.

person Neil Lunn    schedule 06.06.2017
comment
Terima kasih, tetapi bisakah Anda menjelaskan lebih lanjut proses pengelompokannya? Itu berhasil setelah saya mengganti semua nomor dengan satu nomor - person Bazinga777; 06.06.2017
comment
@ Bazinga777 Seharusnya tidak ada bedanya. Berfungsi dengan baik untuk saya dalam JavaScript dan saya melakukannya sepanjang waktu. Apakah ini cara kerja matematika untuk menyelesaikannya menjadi hari yang perlu Anda pahami lebih baik daripada penjelasan saat ini? - person Neil Lunn; 06.06.2017
comment
Masalahnya adalah saya perlu menambahkan offset untuk setiap zona waktu. Saya melewatkan itu dalam pertanyaan saya - person Bazinga777; 06.06.2017
comment
tepatnya, saya ingin tahu matematika - person Bazinga777; 06.06.2017
comment
@ Bazinga777 Oke. Itu sepanjang yang saya bisa sampaikan tanpa terdengar seperti ceramah. Semoga Anda belajar sesuatu. Jadi offset zona waktu Anda harus sesuai dengan tempat Anda mengonversi stempel waktu saat ini dari tipe Date BSON ke tipe numerik. Oleh karena itu, di baris yang sama dengan penggunaan pernyataan $subtract yang berulang. Lakukan itu juga setiap saat. - person Neil Lunn; 06.06.2017
comment
Terima kasih banyak untuk ini. Saya bahkan menemukan cara menghitung offset sekarang - person Bazinga777; 06.06.2017
comment
@ Bazinga777 Bagus untukmu. Saya sebenarnya memiliki beberapa kode yang juga memperhitungkan perubahan waktu musim panas dan membuat penghitungan berbeda melalui $cond dengan rentang tanggal yang melintasi perubahan di suatu tempat. Saya pikir ada jawaban yang beredar di sini di mana saya menunjukkannya, tetapi sepertinya tidak dapat menemukannya. Bagaimanapun, setidaknya Anda memiliki apa yang Anda inginkan saat ini. - person Neil Lunn; 06.06.2017
comment
Saya akan menghargai sumber daya apa pun - person Bazinga777; 06.06.2017