İki tarih arasındaki nesneleri bulma MongoDB


406

Ben mongodb içinde tweets saklamak etrafında oynuyordum, her nesne şöyle görünür:

{
"_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
}

Oluşturulan_at'ı kontrol eden ve 18:47 ile 19:00 arasındaki tüm nesneleri bulan bir sorguyu nasıl yazarım ? Tarihlerin belirli bir biçimde saklanması için belgelerimi güncellemem gerekir mi?


Hangi alanı sorgulamak istediğinizi söylemiyor musunuz?
shingara

Hata! Ben create_at sorgulamak ve tüm iki tarih arasında bulmak istiyorum.
Tom

Merak ettim neden zaman damgası kullanmıyorum, herhangi bir avantaj kullanarak Tarih Obj?
Leo

4
@Leo Çağdan beri tarih nesnesi veya insan tarafından okunabilirlik her ne ise milisaniye boyunca en büyük avantaj. Bu durumda, başlangıç ​​aralığınızı ayarlamak 2010-04-29T00:00:00.000Zaynı tarih / saati milisaniye cinsinden hesaplamaktan çok daha kolaydır. Saat dilimi dönüşümünü de kolayca yapabilirsiniz. Ayrıca Tarihler artık artık günler, artık saniye sayısı ve genellikle kendinizle uğraşmak istemediğiniz diğer tuhaflıklar gibi şeylerle başa çıkıyor.
Thunderforge

Yanıtlar:


619

Bir Tarih Aralığı (Belirli Ay veya Gün) için sorgulama içinde MongoDB Cookbook konuda çok iyi bir açıklaması olduğunu ancak aşağıda kendimi denedim bir şey olduğunu ve işin görünüyor.

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)" }

Deneylerime dayanarak, tarihlerinizi MongoDB'nin desteklediği bir formatta serileştirmeniz gerekecek, çünkü aşağıdakiler istenmeyen arama sonuçları verdi.

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" }

İkinci örnekte hiçbir sonuç beklenmemiştir, ancak yine de bir tane elde edilmiştir. Bunun nedeni, temel bir dize karşılaştırması yapılmasıdır.


3
İlginç görünüyor, ancak depolanan tarihin belirli bir biçimde olması gerekiyor mu? Sadece twitter tarafından sağlananları saklıyorum, bunun farklı bir biçime değiştirilmesi gerekiyor mu?
Tom

7
Muhtemelen zaman damgalarını dizeler olarak sakladınız, bu yüzden MongoDB'nin aslında tarihler olduğunu fark etmeyeceğini tahmin ediyorum. Bu nedenle üzerlerinde bir aralık sorgusu yapmak alfabetik bir aralık sorgusuyla sonuçlanır (örneğin, "Jan Paz 01.01.2010" "Jan Sun 01.01.1000" den önce). Muhtemelen tüm tarih verilerini MongoDB biçiminde biçimlendirmek mantıklı olacaktır, ki bence sadece düz JavaScript Tarihi.
ponzao

2
Bunu sadece dizelerimi tarih nesnelerine dönüştürmek için kullandım stackoverflow.com/questions/2900674/…
Tom

Peki tamam! Yemek kitabında belirtilen aralık sorgularının işe yarayacağını tahmin ediyorum, o zaman zaten denedin mi?
ponzao

Evet, tarihleri ​​saklarken bir kere yemek kitabı örnekleri beklendiği gibi çalıştı.
Tom

35

Netleştirmek için. Bilmek önemli olan şudur:

  • Evet, bir Javascript Date nesnesi iletmeniz gerekiyor.
  • Evet, ISODate dostu olmalı
  • Evet, bunu işe alma deneyimimden, tarihi ISO'ya ayarlamanız gerekiyor
  • Evet, tarihlerle çalışmak her zaman sıkıcı bir süreçtir ve mongo bir istisna değildir

Burada, Mongo'nun (burada mongoose modülünü kullanıyorum ve tarih özniteliği myDate parametresi olarak verilen tarihten (daha önce) daha az olan satırların sonuçlarının işlenebilmesini sağlamak için biraz tarih manipülasyonu yaptığımız, çalışan bir kod snippet'i doğru:

var inputDate = new Date(myDate.toISOString());
MyModel.find({
    'date': { $lte: inputDate }
})

1
Artı netlik için bir tane. Arka uçta kullanım anınız hala toISOString () işlevini korur. Anlarımı sorgularıma zaman eklemek ve çıkarmak için kullanıyorum.
VocoJax

17

MongoDB aslında http://bsonspec.org/#/specification tarafından belirtilen bir tarihin milis değerini int (64) olarak depolar

Ancak, istemci sürücüsü bir tarih nesnesini kendi yerel saat dilimiyle başlatırken tarihleri ​​aldığınızda oldukça kafa karıştırıcı olabilir. Mongo konsolundaki JavaScript sürücüsü kesinlikle bunu yapacaktır.

Bu nedenle, zaman dilimlerinizle ilgileniyorsanız, geri aldığınızda ne olması gerektiğini bildiğinizden emin olun. Tarih nesnenizin hangi saat diliminde olduğuna bakılmaksızın, aynı int (64) 'e eşit olacağı için bu, sorgular için çok önemli olmamalıdır (umarım). Ama kesinlikle gerçek tarih nesneleri (dizeleri değil) ile sorgu yapmak ve sürücünün şey yapmasına izin.


16

Python ve pymongo

pymongoKoleksiyondaki Python'da iki tarih arasındaki nesneleri bulma posts( öğreticiye göre ):

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)

Nerede {"$gte": from_date, "$lt": to_date}aralığı datetime.datetimetür olarak belirtir .


Bu çalışmıyor. Bu sorguyu her çalıştırdığımda varsayılan olarak tam yanıt alıyorum ve filtrelenmemiş yanıt alıyorum
Abhay Bh

14
db.collection.find({"createdDate":{$gte:new ISODate("2017-04-14T23:59:59Z"),$lte:new ISODate("2017-04-15T23:59:59Z")}}).count();

collectionSorguyu yürütmek istediğiniz koleksiyonun adıyla değiştirin


3
Bu, kabul edilen cevaba ne katar (7 yıl önce sağlanmıştır)?
Dan Dascalescu

1
@DanDascalescu -bir şey eklememiş olabilir ama burada endişeniz nedir?
GSK

17
Yinelenen cevaplar insanların zamanını boşa harcar.
Dan Dascalescu

10

$gteVe kullanarak iki tarih arasındaki kaydı bulmak için bu kodu kullanın $lt:

db.CollectionName.find({"whenCreated": {
    '$gte': ISODate("2018-03-06T13:10:40.294Z"),
    '$lt': ISODate("2018-05-06T13:10:40.294Z")
}});

Bu, 8 yıl önce verilen kabul edilen cevaba ne katar?
Dan Dascalescu

7

Moment.js ile kullanma ve Karşılaştırma Sorgusu İşleçleri

  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) { ... });

2

Tarihlerinizi GMT saat dilimine Mongo'ya doldururken dönüştürün. Bu şekilde hiçbir zaman dilimi sorunu olmaz. Ardından, verileri sunum için geri çekerken, twitter / timezone alanındaki matematiği yapın.


2

Neden dizeyi YYYYMMDDHHMMSS formunun bir tamsayısına dönüştürmüyorsunuz? Her zaman artışı daha büyük bir tamsayı oluşturacaktır ve ISO zamanına dönüştürmekten endişe etmek yerine tamsayılara filtre uygulayabilirsiniz.


Çünkü zaman sadece yerel saat dilimimde olmuyor.
Michael Cole

2
Zamanı her yerde bu formata dönüştürmek zorunda kaldığınızda bu bir kabus haline gelir. En azından böyle bir şey yapacaksanız, JS tarih nesnesinden .getTime () dönüş değerini kullanın.
nikk wong

1
bu yüzden verileri her zaman UTC'de
saklarız

2

mongodb'daki tarih verileri arasında bulmak için $ gte ve $ lte kullanın

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")}})

1
Cevabınızdaki hafif yazım hatası $ gte $ $ değil :)
Bob

1
Üzgünüm çok yorgun duruma cevap verdim, bu yüzden hata yaptım. Cevabımı güncelleme konusunda yardımınız için teşekkürler. you did good job :) @Bob
KARTHIKEYAN.A

2

Bunu da kontrol edebilirsiniz. Bu yöntemi kullanıyorsanız, Mongo Veritabanından değer almak için ayrıştırma işlevini kullanın:

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

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`) ]
                        },
                    ]
                 }
              }
           }
        }
     }
])

1

Ayrıca bunu kontrol edebilir veya toplu kullanmak yerine deneyebilirsiniz

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

0

benim ihtiyaçlarına göre bu modelde denedim ben daha sonra bir nesne daha sonra oluşturulduğunda bir tarih depolamak gerekir ben html dosyasında iki tarih arasındaki tüm kayıtları (belgeleri) almak istiyorum ben aşağıdaki biçimi kullanıyordum mm / dd / yyyy

<!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>

benim py (python) dosyasında aşağıdaki şekilde "iso fomate" dönüştürdüm

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

ve koleksiyonumdaki alan olarak "SelectedDate" ile dbmongo koleksiyonuma kaydedildim

2 sorgu arasında veri veya belge almak için aşağıdaki sorguyu kullandım

db.collection.find( "SelectedDate": {'$gte': SelectedDate1,'$lt': SelectedDate2}})
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.