Temukan objek antara dua tanggal MongoDB

406

Saya telah bermain-main menyimpan tweet di dalam mongodb, setiap objek terlihat seperti ini:

{
"_id" : ObjectId("4c02c58de500fe1be1000005"),
"contributors" : null,
"text" : "Hello world",
"user" : {
    "following" : null,
    "followers_count" : 5,
    "utc_offset" : null,
    "location" : "",
    "profile_text_color" : "000000",
    "friends_count" : 11,
    "profile_link_color" : "0000ff",
    "verified" : false,
    "protected" : false,
    "url" : null,
    "contributors_enabled" : false,
    "created_at" : "Sun May 30 18:47:06 +0000 2010",
    "geo_enabled" : false,
    "profile_sidebar_border_color" : "87bc44",
    "statuses_count" : 13,
    "favourites_count" : 0,
    "description" : "",
    "notifications" : null,
    "profile_background_tile" : false,
    "lang" : "en",
    "id" : 149978111,
    "time_zone" : null,
    "profile_sidebar_fill_color" : "e0ff92"
},
"geo" : null,
"coordinates" : null,
"in_reply_to_user_id" : 149183152,
"place" : null,
"created_at" : "Sun May 30 20:07:35 +0000 2010",
"source" : "web",
"in_reply_to_status_id" : {
    "floatApprox" : 15061797850
},
"truncated" : false,
"favorited" : false,
"id" : {
    "floatApprox" : 15061838001
}

Bagaimana cara saya menulis kueri yang memeriksa Created_at dan menemukan semua objek antara 18:47 dan 19:00? Apakah saya perlu memperbarui dokumen saya sehingga tanggal disimpan dalam format tertentu?

Tom
sumber
Anda tidak mengatakan tentang bidang yang Anda inginkan permintaan?
shingara
Ups, saya ingin meminta create_at dan menemukan semua di antara dua tanggal.
Tom
Saya ingin tahu mengapa tidak menggunakan cap waktu, apakah ada keuntungan dengan menggunakan Date Obj?
Leo
4
@ Leo Keuntungan terbesar dengan objek Date selama milidetik sejak zaman atau apa pun yang dapat dibaca manusia. Dalam hal ini, mengatur rentang awal Anda menjadi 2010-04-29T00:00:00.000Zjauh lebih mudah daripada menghitung tanggal / waktu yang sama dalam milidetik. Anda juga dapat melakukan konversi zona waktu dengan cukup mudah. Juga, Tanggal sudah menangani hal-hal seperti hari kabisat, detik kabisat, dan keanehan lain yang biasanya tidak ingin Anda tangani sendiri.
Thunderforge

Jawaban:

620

Meminta Rentang Tanggal (Bulan atau Hari Tertentu) dalam Buku Masak MongoDB memiliki penjelasan yang sangat baik tentang masalah ini, tetapi di bawah ini adalah sesuatu yang saya coba sendiri dan sepertinya berhasil.

items.save({
    name: "example",
    created_at: ISODate("2010-04-30T00:00:00.000Z")
})
items.find({
    created_at: {
        $gte: ISODate("2010-04-29T00:00:00.000Z"),
        $lt: ISODate("2010-05-01T00:00:00.000Z")
    }
})
=> { "_id" : ObjectId("4c0791e2b9ec877893f3363b"), "name" : "example", "created_at" : "Sun May 30 2010 00:00:00 GMT+0300 (EEST)" }

Berdasarkan eksperimen saya, Anda perlu membuat serial tanggal Anda ke dalam format yang didukung MongoDB, karena yang berikut memberikan hasil pencarian yang tidak diinginkan.

items.save({
    name: "example",
    created_at: "Sun May 30 18.49:00 +0000 2010"
})
items.find({
    created_at: {
        $gte:"Mon May 30 18:47:00 +0000 2015",
        $lt: "Sun May 30 20:40:36 +0000 2010"
    }
})
=> { "_id" : ObjectId("4c079123b9ec877893f33638"), "name" : "example", "created_at" : "Sun May 30 18.49:00 +0000 2010" }

Dalam contoh kedua tidak ada hasil yang diharapkan, tetapi masih ada satu yang didapat. Ini karena perbandingan string dasar dilakukan.

ponzao
sumber
3
Terlihat menarik, tetapi apakah tanggal yang disimpan harus dalam format tertentu. Saya baru saja menyimpan apa yang disediakan oleh twitter, apakah ini perlu diubah menjadi format yang berbeda?
Tom
7
Anda mungkin menyimpan stempel waktu sebagai string, jadi saya kira MongoDB tidak akan menyadari bahwa mereka sebenarnya adalah tanggal. Dengan demikian melakukan kueri rentang pada mereka akan menghasilkan kueri rentang alfabet (misalnya "Jan Mon 01.01.2010" sebelum "Jan Sun 01.01.1000"). Mungkin masuk akal untuk memformat semua data tanggal ke dalam format MongoDB, yang menurut saya hanya JavaScript Tanggal.
ponzao
2
Saya hanya menggunakan ini untuk mengkonversi string saya ke objek tanggal stackoverflow.com/questions/2900674/...
Tom
Oke keren! Saya kira rentang pertanyaan yang disebutkan dalam buku masak harusnya berhasil, apakah Anda sudah mencobanya?
ponzao
Yap begitu saya menyimpan tanggal benar contoh buku masak bekerja seperti yang diharapkan.
Tom
35

Untuk memperjelas. Yang penting diketahui adalah:

  • Ya, Anda harus melewati objek Tanggal Javascript.
  • Ya, itu harus ramah ISODate
  • Ya, dari pengalaman saya membuat ini berfungsi, Anda perlu memanipulasi tanggal ke ISO
  • Ya, bekerja dengan teman kencan selalu merupakan proses yang membosankan, dan mongo tidak terkecuali

Berikut ini adalah potongan kode yang berfungsi, di mana kami melakukan sedikit manipulasi tanggal untuk memastikan Mongo (di sini saya menggunakan modul luwak dan ingin hasil untuk baris yang atribut tanggalnya kurang dari (sebelum) tanggal yang diberikan sebagai parameter myDate) dapat menangani dengan benar:

var inputDate = new Date(myDate.toISOString());
MyModel.find({
    'date': { $lte: inputDate }
})
arcseldon
sumber
1
Ditambah satu untuk kejelasan. Jika momen penggunaan Anda di backend, ia masih mempertahankan fungsi toISOString (). Saya menggunakan momen untuk menambah dan mengurangi waktu untuk pertanyaan saya.
VocoJax
17

MongoDB sebenarnya menyimpan mili tanggal sebagai int (64), seperti yang ditentukan oleh http://bsonspec.org/#/specification

Namun, itu bisa sangat membingungkan ketika Anda mengambil tanggal karena driver klien akan instantiate objek tanggal dengan zona waktu lokal sendiri. Driver JavaScript di konsol mongo pasti akan melakukan ini.

Jadi, jika Anda peduli dengan zona waktu Anda, maka pastikan Anda tahu apa yang seharusnya ketika Anda mendapatkannya kembali. Ini seharusnya tidak terlalu menjadi masalah bagi kueri, karena masih akan menyamakan ke int yang sama (64), terlepas dari apa zona waktu objek kencan Anda (saya harap). Tapi saya pasti akan membuat pertanyaan dengan objek tanggal aktual (bukan string) dan membiarkan pengemudi melakukan hal itu.

Ben Smith
sumber
16

Python dan pymongo

Menemukan objek antara dua tanggal dalam Python dengan pymongodalam koleksi posts(berdasarkan tutorial ):

from_date = datetime.datetime(2010, 12, 31, 12, 30, 30, 125000)
to_date = datetime.datetime(2011, 12, 31, 12, 30, 30, 125000)

for post in posts.find({"date": {"$gte": from_date, "$lt": to_date}}):
    print(post)

Di mana {"$gte": from_date, "$lt": to_date}menentukan kisaran dalam hal datetime.datetimejenis.

Anton Tarasenko
sumber
Ini tidak bekerja. Setiap kali saya menjalankan kueri ini, saya mendapatkan respons lengkap default dan tidak menyaring respons
Abhay Bh
14
db.collection.find({"createdDate":{$gte:new ISODate("2017-04-14T23:59:59Z"),$lte:new ISODate("2017-04-15T23:59:59Z")}}).count();

Ganti collectiondengan nama koleksi yang ingin Anda jalankan kueri

GSK
sumber
3
Apa yang ini tambahkan ke jawaban yang diterima (disediakan 7 tahun sebelumnya)?
Dan Dascalescu
1
@DanDascalescu -mungkin itu tidak menambahkan apa-apa tapi apa yang menjadi perhatian Anda di sini?
GSK
17
Jawaban duplikat menghabiskan waktu orang.
Dan Dascalescu
10

Gunakan kode ini untuk menemukan catatan antara dua tanggal menggunakan $gtedan $lt:

db.CollectionName.find({"whenCreated": {
    '$gte': ISODate("2018-03-06T13:10:40.294Z"),
    '$lt': ISODate("2018-05-06T13:10:40.294Z")
}});
Sunil Pal
sumber
Apa yang ini tambahkan ke jawaban yang diterima, asalkan 8 tahun sebelumnya?
Dan Dascalescu
7

Menggunakan dengan Moment.js dan Operator Kueri Perbandingan

  var today = moment().startOf('day');
  // "2018-12-05T00:00:00.00
  var tomorrow = moment(today).endOf('day');
  // ("2018-12-05T23:59:59.999

  Example.find(
  {
    // find in today
    created: { '$gte': today, '$lte': tomorrow }
    // Or greater than 5 days
    // created: { $lt: moment().add(-5, 'days') },
  }), function (err, docs) { ... });
Tính Ngô Quang
sumber
2

Ubah tanggal Anda menjadi zona waktu GMT saat Anda memasukkannya ke dalam bahasa Mongo. Dengan begitu tidak pernah ada masalah zona waktu. Kemudian lakukan perhitungan di bidang twitter / zona waktu ketika Anda menarik kembali data untuk presentasi.

mulai sekarang
sumber
2

Mengapa tidak mengonversi string ke integer dari bentuk YYYYMMDDHHMMSS? Setiap penambahan waktu kemudian akan membuat bilangan bulat yang lebih besar, dan Anda dapat memfilter bilangan bulat alih-alih mengkhawatirkan konversi ke waktu ISO.

ZacharyST
sumber
Karena waktu tidak hanya terjadi di zona waktu lokal saya.
Michael Cole
2
Ini menjadi mimpi buruk begitu Anda mulai harus mengubah waktu ke dan dari format itu di mana-mana. Jika Anda akan melakukan sesuatu seperti ini setidaknya gunakan nilai pengembalian dari .getTime () dari objek tanggal JS.
nikk wong
1
Itulah sebabnya kami selalu menyimpan data dalam UTC
codewandler
2

gunakan $ gte dan $ lte untuk menemukan antara data tanggal di mongodb

var tomorrowDate = moment(new Date()).add(1, 'days').format("YYYY-MM-DD");
db.collection.find({"plannedDeliveryDate":{ $gte: new Date(tomorrowDate +"T00:00:00.000Z"),$lte: new Date(tomorrowDate + "T23:59:59.999Z")}})
KARTHIKEYAN.A
sumber
1
Sedikit kesalahan ketik dalam jawaban Anda $ gte bukan $ get :)
Bob
1
Maaf saya menjawab kondisi sangat lelah, jadi saya membuat kesalahan. Terima kasih atas bantuan Anda untuk memperbarui jawaban saya. Anda melakukan pekerjaan dengan baik :) @ Bob
KARTHIKEYAN.A
2

Anda juga dapat memeriksanya. Jika Anda menggunakan metode ini, gunakan fungsi parse untuk mendapatkan nilai dari Database Mongo:

db.getCollection('user').find({
    createdOn: {
        $gt: ISODate("2020-01-01T00:00:00.000Z"),
        $lt: ISODate("2020-03-01T00:00:00.000Z")
    }
})
Kevin007
sumber
1
mongoose.model('ModelName').aggregate([
    {
        $match: {
            userId: mongoose.Types.ObjectId(userId)
        }
    },
    {
        $project: {
            dataList: {
              $filter: {
                 input: "$dataList",
                 as: "item",
                 cond: { 
                    $and: [
                        {
                            $gte: [ "$$item.dateTime", new Date(`2017-01-01T00:00:00.000Z`) ]
                        },
                        {
                            $lte: [ "$$item.dateTime", new Date(`2019-12-01T00:00:00.000Z`) ]
                        },
                    ]
                 }
              }
           }
        }
     }
])
Jitendra
sumber
1

Anda juga dapat memeriksa ini atau mencoba daripada menggunakan agregat

db.getCollection('user').find({
    createdOn: {
        $gt: ISODate("2020-01-01T00:00:00.000Z"),
        $lt: ISODate("2020-03-01T00:00:00.000Z")
    }
})
Kevin007
sumber
0

saya mencoba dalam model ini sesuai kebutuhan saya, saya perlu menyimpan tanggal ketika suatu objek dibuat nanti saya ingin mengambil semua catatan (dokumen) antara dua tanggal dalam file html saya saya menggunakan format berikut mm / hh / tttt

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>

    <script>
//jquery
    $(document).ready(function(){  
    $("#select_date").click(function() { 
    $.ajax({
    type: "post",
    url: "xxx", 
    datatype: "html",
    data: $("#period").serialize(),  
    success: function(data){
    alert(data);
    } ,//success

    }); //event triggered

    });//ajax
    });//jquery  
    </script>

    <title></title>
</head>

<body>
    <form id="period" name='period'>
        from <input id="selecteddate" name="selecteddate1" type="text"> to 
        <input id="select_date" type="button" value="selected">
    </form>
</body>
</html>

dalam file py (python) saya, saya mengubahnya menjadi "iso fomate" dengan cara berikut

date_str1   = request.POST["SelectedDate1"] 
SelectedDate1   = datetime.datetime.strptime(date_str1, '%m/%d/%Y').isoformat()

dan disimpan dalam koleksi dbmongo saya dengan "SelectedDate" sebagai bidang dalam koleksi saya

untuk mengambil data atau dokumen antara hingga 2 tanggal saya menggunakan permintaan berikut

db.collection.find( "SelectedDate": {'$gte': SelectedDate1,'$lt': SelectedDate2}})
ayu untukmu
sumber