MongoDB
 sql >> Teknologi Basis Data >  >> NoSQL >> MongoDB

Temukan apakah seseorang berulang tahun dalam 30 hari ke depan dengan mongo

Kerangka kerja agregasi pasti pendekatan yang tepat - apa pun yang memerlukan JS di server adalah masalah kinerja, sementara semua agregasi berjalan di server dalam kode asli.

Meskipun mungkin untuk mengubah ulang tahun menjadi tanggal ulang tahun yang akan datang dan kemudian melakukan kueri rentang, saya lebih suka melakukannya dengan cara yang sedikit berbeda.

Satu-satunya "prasyarat adalah menghitung hari hari ini dalam setahun". Ada cara untuk melakukan ini dalam berbagai bahasa, jadi ini bisa dilakukan di lapisan aplikasi sebelum memanggil agregasi, meneruskan nomor ini ke sana. Saya akan menelepon saya todayDayOfYear tetapi saya menyadari bahwa Anda dapat membiarkan kerangka kerja agregasi mengetahuinya berdasarkan hari ini, jadi satu-satunya variabel adalah tanggal hari ini.

var today=new Date();

Saya berasumsi dokumen yang menyertakan nama dan tanggal lahir, sesuaikan dengan tepat untuk variasi

var p1 = { "$project" : {
            "_id" : 0,
            "name" : 1,
            "birthday" : 1,
            "todayDayOfYear" : { "$dayOfYear" : today }, 
            "dayOfYear" : { "$dayOfYear" : "$birthday"}
} };

Sekarang, proyeksikan berapa hari dari hari ini hingga ulang tahun mereka berikutnya:

var p2 = { "$project" : {
        "name" : 1,
        "birthday" : 1,
        "daysTillBirthday" : { "$subtract" : [
             { "$add" : [ 
                     "$dayOfYear",
             { "$cond" : [{"$lt":["$dayOfYear","$todayDayOfYear"]},365,0 ] }
             ] },
             "$todayDayOfYear"
        ] }
} };

Kecualikan semua kecuali yang berada dalam rentang yang diinginkan:

var m = { "$match" : { "daysTillBirthday" : { "$lt" : 31 } } };

Sekarang jalankan agregasi dengan:

db.collection.aggregate( p1, p2, m );

untuk mendapatkan kembali daftar nama, ulang tahun, dan hari hingga ulang tahun untuk semua orang yang beruntung yang ulang tahunnya dalam waktu 30 hari.

EDIT

@Sean999 menangkap kasus tepi yang menarik - orang yang lahir di tahun kabisat setelah 28 Februari akan kehilangan perhitungannya satu per satu. Berikut ini adalah agregasi yang menyesuaikan dengan benar untuk itu:

var p1 = { "$project" : { 
            "_id" : 0,
            "name" : 1,
            "birthday" : 1, 
            "todayDayOfYear" : { "$dayOfYear" : ISODate("2014-03-09T12:30:51.515Z") },
            "leap" : { "$or" : [ 
                  { "$eq" : [ 0, { "$mod" : [ { "$year" : "$birthday" }, 400 ] } ] }, 
                  { "$and" : [ 
                        { "$eq" : [ 0, { "$mod" : [ { "$year" : "$birthday" }, 4 ] } ] }, 
                        { "$ne" : [ 0, { "$mod" : [ { "$year" : "$birthday" }, 100 ] } ] } ] } ] },
            "dayOfYear" : { "$dayOfYear" : "$birthday" } } };

var p1p = { "$project" : {
                "name" : 1,
                "birthday" : 1,
                "todayDayOfYear" : 1,
                "dayOfYear" : { "$subtract" : [ 
                      "$dayOfYear", 
                      { "$cond" : [ { "$and" : [ "$leap", { "$gt" : [ "$dayOfYear", 59 ] } ] }, 1, 0 ] } ] }
        }
}

p2 dan m tetap sama seperti di atas.

Masukan pengujian:

db.birthdays.find({},{name:1,birthday:1,_id:0})
{ "name" : "Ally", "birthday" : ISODate("1975-06-12T00:00:00Z") }
{ "name" : "Ben", "birthday" : ISODate("1968-04-03T00:00:00Z") }
{ "name" : "Mark", "birthday" : ISODate("1949-12-23T00:00:00Z") }
{ "name" : "Paul", "birthday" : ISODate("2014-03-04T15:59:05.374Z") }
{ "name" : "Paul", "birthday" : ISODate("2011-02-07T00:00:00Z") }
{ "name" : "Sean", "birthday" : ISODate("2004-01-31T00:00:00Z") }
{ "name" : "Tim", "birthday" : ISODate("2008-02-28T00:00:00Z") }
{ "name" : "Sandy", "birthday" : ISODate("2005-01-31T00:00:00Z") }
{ "name" : "Toni", "birthday" : ISODate("2009-02-28T00:00:00Z") }
{ "name" : "Sam", "birthday" : ISODate("2005-03-31T00:00:00Z") }
{ "name" : "Max", "birthday" : ISODate("2004-03-31T00:00:00Z") }
{ "name" : "Jen", "birthday" : ISODate("1971-04-03T00:00:00Z") }
{ "name" : "Ellen", "birthday" : ISODate("1996-02-28T00:00:00Z") }
{ "name" : "Fanny", "birthday" : ISODate("1996-02-29T00:00:00Z") }
{ "name" : "Gene", "birthday" : ISODate("1996-03-01T00:00:00Z") }
{ "name" : "Edgar", "birthday" : ISODate("1997-02-28T00:00:00Z") }
{ "name" : "George", "birthday" : ISODate("1997-03-01T00:00:00Z") }

Keluaran:

db.birthdays.aggregate( p1, p1p, p2, {$sort:{daysTillBirthday:1}});
{ "name" : "Sam", "birthday" : ISODate("2005-03-31T00:00:00Z"), "daysTillBirthday" : 22 }
{ "name" : "Max", "birthday" : ISODate("2004-03-31T00:00:00Z"), "daysTillBirthday" : 22 }
{ "name" : "Ben", "birthday" : ISODate("1968-04-03T00:00:00Z"), "daysTillBirthday" : 25 }
{ "name" : "Jen", "birthday" : ISODate("1971-04-03T00:00:00Z"), "daysTillBirthday" : 25 }
{ "name" : "Ally", "birthday" : ISODate("1975-06-12T00:00:00Z"), "daysTillBirthday" : 95 }
{ "name" : "Mark", "birthday" : ISODate("1949-12-23T00:00:00Z"), "daysTillBirthday" : 289 }
{ "name" : "Sean", "birthday" : ISODate("2004-01-31T00:00:00Z"), "daysTillBirthday" : 328 }
{ "name" : "Sandy", "birthday" : ISODate("2005-01-31T00:00:00Z"), "daysTillBirthday" : 328 }
{ "name" : "Paul", "birthday" : ISODate("2011-02-07T00:00:00Z"), "daysTillBirthday" : 335 }
{ "name" : "Tim", "birthday" : ISODate("2008-02-28T00:00:00Z"), "daysTillBirthday" : 356 }
{ "name" : "Toni", "birthday" : ISODate("2009-02-28T00:00:00Z"), "daysTillBirthday" : 356 }
{ "name" : "Ellen", "birthday" : ISODate("1996-02-28T00:00:00Z"), "daysTillBirthday" : 356 }
{ "name" : "Fanny", "birthday" : ISODate("1996-02-29T00:00:00Z"), "daysTillBirthday" : 356 }
{ "name" : "Edgar", "birthday" : ISODate("1997-02-28T00:00:00Z"), "daysTillBirthday" : 356 }
{ "name" : "Gene", "birthday" : ISODate("1996-03-01T00:00:00Z"), "daysTillBirthday" : 357 }
{ "name" : "George", "birthday" : ISODate("1997-03-01T00:00:00Z"), "daysTillBirthday" : 357 }
{ "name" : "Paul", "birthday" : ISODate("2014-03-04T15:59:05.374Z"), "daysTillBirthday" : 360 }

Anda dapat melihat bahwa orang-orang dengan hari ulang tahun yang sama sekarang memiliki jumlah hari yang sama sampai ulang tahun apakah mereka lahir pada tahun kabisat atau tidak. Langkah pencocokan sekarang dapat dilakukan untuk cut-off yang dirancang.

EDIT

Pada versi 3.5.11 ada beberapa ekspresi manipulasi tanggal dalam pipa agregasi yang membuatnya lebih mudah untuk ditulis. Secara khusus, ekspresi $dateFromParts memungkinkan pembuatan tanggal dari berbagai bagian, memungkinkan agregasi ini:

var today = new Date();
var a1 = {$addFields:{
    today:{$dateFromParts:{year:{$year:today},month:{$month:today},day:{$dayOfMonth:today}}},
    birthdayThisYear:{$dateFromParts:{year:{$year:today}, month:{$month:"$birthday"}, day:{$dayOfMonth:"$birthday"}}}, 
    birthdayNextYear:{$dateFromParts:{year:{$add:[1,{$year:today}]}, month:{$month:"$birthday"}, day:{$dayOfMonth:"$birthday"}}}
}};
var a2 = {$addFields:{
    nextBirthday:{$cond:[ {$gte:[ "$birthdayThisYear", "$today"]}, "$birthdayThisYear", "$birthdayNextYear"]}
}};
var p1 = {$project:{
    name:1, 
    birthday:1, 
    daysTillNextBirthday:{$divide:[ 
        {$subtract:["$nextBirthday", "$today"]}, 
        24*60*60*1000  /* milliseconds in a day */
     ]}, 
    _id:0
}};
var s1 = {$sort:{daysTillNextBirthday:1}};
db.birthdays.aggregate([ a1, a2, p1, s1 ]);

Anda dapat mengatur "hari ini" ke tanggal mana pun (tahun kabisat atau tidak) dan melihat bahwa perhitungannya sekarang selalu benar dan jauh lebih sederhana.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Klien GUI MongoDB (lintas platform atau Linux)

  2. Penyatuan koneksi database MongoDB Java Driver dengan Tomcat

  3. hapus _id dari hasil mongo

  4. MongoDB, hapus objek dari array

  5. $lookup beberapa level tanpa $unwind?