Trova oggetti tra due date MongoDB


406

Ho giocato per memorizzare i tweet all'interno di mongodb, ogni oggetto è simile al seguente:

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

Come potrei scrivere una query che controlla il Created_at e trova tutti gli oggetti tra le 18:47 e le 19:00? Devo aggiornare i miei documenti in modo che le date siano memorizzate in un formato specifico?


Non dici di quale campo vuoi fare una query?
shingara,

Oops, voglio interrogare il creato_at e trovare tutto tra due date.
Tom,

Sono curioso di sapere perché non usare il timestamp, qualche vantaggio usando il Date Obj?
Leo,

4
@Leo Il più grande vantaggio con l'oggetto Date nell'arco di millisecondi dall'epoca o qualunque sia la leggibilità umana. In questo caso, impostare l'intervallo iniziale su 2010-04-29T00:00:00.000Zè molto più semplice rispetto al calcolo della stessa data / ora in millisecondi. Puoi anche fare la conversione del fuso orario abbastanza facilmente. Inoltre, le date gestiscono già cose come i giorni bisestili, i secondi intercalari e altre stranezze che di solito non si desidera gestire.
Thunderforge il

Risposte:


620

Interrogare per un intervallo di date (mese o giorno specifico) nel ricettario MongoDB ha un'ottima spiegazione in merito, ma di seguito è qualcosa che ho provato io stesso e sembra funzionare.

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

Sulla base dei miei esperimenti dovrai serializzare le tue date in un formato supportato da MongoDB, poiché i seguenti risultati di ricerca indesiderati.

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

Nel secondo esempio non ci si aspettava risultati, ma ce n'era ancora uno ottenuto. Questo perché viene eseguito un confronto di stringhe di base.


3
Sembra interessante, ma la data memorizzata deve essere in un formato specifico. Ho appena memorizzato ciò che è stato fornito da Twitter, questo deve essere cambiato in un formato diverso?
Tom,

7
Probabilmente hai memorizzato i timestamp come stringhe, quindi suppongo che MongoDB non si renderà conto che in realtà sono date. Pertanto, eseguendo una query di intervallo su di essi si tradurrebbe in una query di intervallo alfabetica (ad es. "Jan lun 01.01.2010" prima di "Jan dom 01.01.1000"). Probabilmente avrebbe senso formattare tutti i dati relativi alla data nel formato MongoDB, che credo sia semplicemente una semplice JavaScript Date.
ponzao,

2
Ho appena usato questo per convertire le mie stringhe in oggetti data stackoverflow.com/questions/2900674/…
Tom

Va bene, d'accordo! Immagino che le domande sulla gamma menzionate nel ricettario dovrebbero funzionare allora, le hai già provate?
ponzao,

Sì, una volta stavo memorizzando le date corrette, gli esempi di libri di cucina hanno funzionato come previsto.
Tom,

35

Chiarire. Ciò che è importante sapere è che:

  • Sì, devi passare un oggetto Date Javascript.
  • Sì, deve essere ISODate friendly
  • Sì, dalla mia esperienza per far funzionare tutto ciò, è necessario modificare la data in ISO
  • Sì, lavorare con le date è generalmente sempre un processo noioso e mongo non fa eccezione

Ecco un frammento di codice funzionante, in cui facciamo un po 'di manipolazione della data per garantire che Mongo (qui sto usando il modulo mongoose e voglio risultati per le righe il cui attributo date è inferiore a (prima) la data indicata come parametro myDate) in grado di gestire correttamente:

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

1
Più uno per chiarezza. Se stai usando il momento nel backend, mantiene comunque la funzione toISOString (). Uso il momento per aggiungere e sottrarre tempo per le mie domande.
VocoJax,

17

MongoDB in realtà memorizza i millis di una data come int (64), come prescritto da http://bsonspec.org/#/specification

Tuttavia, può diventare piuttosto confuso quando si recuperano le date poiché il driver client crea un'istanza di un oggetto data con il proprio fuso orario locale. Il driver JavaScript nella console mongo lo farà sicuramente.

Quindi, se ti importa dei tuoi fusi orari, assicurati di sapere cosa dovrebbe essere quando lo riavrai. Questo non dovrebbe importare molto per le query, poiché equivarrà comunque allo stesso int (64), indipendentemente dal fuso orario in cui si trova l'oggetto data (spero). Ma sicuramente farei query con oggetti data effettivi (non stringhe) e lascerei che il driver faccia la sua cosa.


16

Python e pymongo

Trovare oggetti tra due date in Python con pymongoin collection posts(basato sul 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)

Dove {"$gte": from_date, "$lt": to_date}specifica l'intervallo in termini di datetime.datetimetipi.


Questo non sta funzionando. Ogni volta che eseguo questa query ricevo per impostazione predefinita una risposta completa e una risposta non filtrata
Abhay Bh,

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

Sostituisci collectioncon il nome della raccolta che desideri eseguire la query


3
Che cosa aggiunge questo alla risposta accettata (fornita 7 anni prima)?
Dan Dascalescu,

1
@DanDascalescu -può non aggiungere nulla ma qual è la tua preoccupazione qui?
GSK,

17
Le risposte duplicate fanno perdere tempo alle persone.
Dan Dascalescu,

10

Usa questo codice per trovare il record tra due date usando $gtee $lt:

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

Che cosa aggiunge questo alla risposta accettata, fornita 8 anni prima?
Dan Dascalescu,

7

Utilizzo con Moment.js e operatori di query di confronto

  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

Converti le tue date nel fuso orario GMT mentre le stai inserendo in Mongo. In questo modo non c'è mai un problema di fuso orario. Quindi fai i calcoli sul campo Twitter / fuso orario quando estrai i dati per la presentazione.


2

Perché non convertire la stringa in un numero intero nel formato AAAAMMGGHHMMSS? Ogni incremento di tempo creerebbe quindi un numero intero più grande e sarà possibile filtrare i numeri interi invece di preoccuparsi della conversione in tempo ISO.


Perché il tempo non sta solo accadendo nel mio fuso orario locale.
Michael Cole,

2
Questo diventa un incubo quando inizi a dover convertire il tempo da e verso quel formato ovunque. Se hai intenzione di fare qualcosa del genere, utilizza almeno il valore restituito da .getTime () da un oggetto data JS.
Nikk Wong,

1
ecco perché archiviamo sempre i dati in UTC
codewandler,

2

usa $ gte e $ lte per trovare tra i dati della data in 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")}})

1
Leggero refuso nella tua risposta $ gte non $ get :)
Bob

1
Mi dispiace di aver risposto a una condizione molto stanca, quindi ho fatto un errore. Grazie per il vostro aiuto per aggiornare la mia risposta. hai fatto un buon lavoro :) @Bob
KARTHIKEYAN.A

2

Puoi anche dare un'occhiata. Se si utilizza questo metodo, utilizzare la funzione di analisi per ottenere valori dal database Mongo:

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

Puoi anche controllare questo o provare invece di usare aggregato

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

0

ho provato in questo modello secondo i miei requisiti ho bisogno di memorizzare una data ogni volta che un oggetto viene creato in seguito voglio recuperare tutti i record (documenti) tra due date nel mio file html che stavo usando il seguente formato mm / gg / aaaa

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

nel mio file py (python) l'ho convertito in "iso fomate" nel modo seguente

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

e salvato nella mia raccolta dbmongo con "SelectedDate" come campo nella mia raccolta

per recuperare dati o documenti tra 2 date ho usato la seguente query

db.collection.find( "SelectedDate": {'$gte': SelectedDate1,'$lt': SelectedDate2}})
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.