MongoDB / Mongoose interrogando ad una data specifica?


141

È possibile richiedere una data specifica?

Ho trovato nel ricettario mongo che possiamo farlo per un intervallo Interrogazione per un intervallo di date In questo modo:

db.posts.find({"created_on": {"$gte": start, "$lt": end}})

Ma è possibile per una data specifica? Questo non funziona:

db.posts.find({"created_on": new Date(2012, 7, 14) })

Risposte:


213

Ciò dovrebbe funzionare se le date salvate nel DB sono senza tempo (solo anno, mese, giorno).

È probabile che le date salvate fossero new Date(), tra cui i componenti dell'ora. Per eseguire una query su tali orari è necessario creare un intervallo di date che includa tutti i momenti di un giorno.

db.posts.find( //query today up to tonight
  {"created_on": {"$gte": new Date(2012, 7, 14), "$lt": new Date(2012, 7, 15)}})

29
Ricorda che nella funzione Date (), l'argomento mese inizia a contare su 0, non su 1. D'altra parte, i giorni iniziano a contare su 1 ... dettagli
Mark Stosberg

non è meglio fare _ 1 giorno per ottenere la prossima data anziché il codice fisso di entrambi?
raju,

2
Questo metodo funziona bene se la data è memorizzata in questo modo: >> "date": ISODate ("2016-01-04T14: 07: 17.496Z")
santhosh,

Non hai i tuoi mesi e le date cambia. Il formato delle date dovrebbe essere: aaaa, gg, MM
thethakuri

124

... 5+ anni dopo, suggerisco caldamente di usare date-fns invece

import endOfDayfrom 'date-fns/endOfDay'
import startOfDay from 'date-fns/startOfDay'

MyModel.find({
  createdAt: {
    $gte: startOfDay(new Date()),
    $lte: endOfDay(new Date())
  }
})

Per quelli di noi che usano Moment.js

const moment = require('moment')

const today = moment().startOf('day')

MyModel.find({
  createdAt: {
    $gte: today.toDate(),
    $lte: moment(today).endOf('day').toDate()
  }
})

Importante: tutti i momenti sono mutabili !

tomorrow = today.add(1, 'days')non funziona poiché muta anche today. Chiamare moment(today)risolve questo problema clonando implicitamente today.


14
Suggerisco di usare .startOf('day')invece di .hours (0) .minutes (0) .seconds (0). Quindi la prima riga sarebbe:var today = moment().startOf('day')
Jim Geurts,

2
Se stiamo usando moment(today)per clonare l'oggetto, un'altra soluzione è:var tomorrow = today.clone().add(1, 'days')
johntellsall,

1
@johntellsall Clonazione esplicita piuttosto che implicita, stesso risultato ma forse più facile da leggere!
Pier-Luc Gendreau,

1
In alternativa, potrei suggerire quanto segue per $lt: moment(today).endOf('day'). Per impedire l'inclusione dei risultati effettivi a partire dal giorno successivo.
greduan,

1
per me moment(today).endOf('day')dà lo stesso giorno con il tempo di: 23:59:59.999. Quindi in realtà sembra più corretto da usare $lte, altrimenti gli oggetti in quel particolare momento verranno ignorati.
leonprou,

11

Sì, l'oggetto Date è conforme alla data e all'ora, quindi il confronto con il solo valore della data non funziona.

Puoi semplicemente usare l' operatore $ where per esprimere condizioni più complesse con l'espressione booleana di Javascript :)

db.posts.find({ '$where': 'this.created_on.toJSON().slice(0, 10) == "2012-07-14"' })

created_onè il campo datetime ed 2012-07-14è la data specificata.

La data deve essere esattamente nel formato AAAA-MM-GG .

Nota: utilizzare $wherecon parsimonia, ha conseguenze sulle prestazioni.


10

Hai provato:

db.posts.find({"created_on": {"$gte": new Date(2012, 7, 14), "$lt": new Date(2012, 7, 15)}})

Il problema che incontrerai è che le date sono memorizzate come indicatori di data e ora in Mongo. Quindi, per abbinare una data stai chiedendo di abbinare un timestamp. Nel tuo caso, penso che stai cercando di abbinare un giorno (ad es. Dalle 00:00 alle 23:59 in una data specifica). Se le tue date sono memorizzate senza orari, allora dovresti essere a posto. Altrimenti, prova a specificare la tua data come intervallo di tempo nello stesso giorno (es. Inizio = 00: 00, fine = 23: 59) se gte non funziona.

domanda simile


1
Ciò includerà tutti gli elementi più giovani della data specificata, che probabilmente non è ciò che OP voleva. Valuta di aggiungere un'opzione "lt" come le altre risposte.
BenSower,

Penso che se hai $gteinvece gtesarebbe meglio.
jack in bianco

Questa risposta ha già ricevuto una risposta più corretta in precedenza, ma mi dava fastidio sapere che la mia risposta era disattivata, quindi l'ho aggiornata per essere corretta per la domanda. Ehi, sono passati 4 anni. lol
Michael D Johnson,

6

È possibile utilizzare il seguente approccio per il metodo API per ottenere risultati da un giorno specifico:

# [HTTP GET]
getMeals: (req, res) ->
  options = {}
  # eg. api/v1/meals?date=Tue+Jan+13+2015+00%3A00%3A00+GMT%2B0100+(CET)
  if req.query.date?
    date = new Date req.query.date
    date.setHours 0, 0, 0, 0
    endDate = new Date date
    endDate.setHours 23, 59, 59, 59
    options.date =
      $lt: endDate
      $gte: date

  Meal.find options, (err, meals) ->
      if err or not meals
        handleError err, meals, res
      else
        res.json createJSON meals, null, 'meals'

1

Abbiamo riscontrato un problema relativo ai dati duplicati nel nostro database, con un campo data con più valori in cui dovevamo avere 1. Ho pensato di aggiungere il modo in cui abbiamo risolto il problema come riferimento.

Abbiamo una raccolta chiamata "dati" con un campo "valore" numerico e un campo "data" data. Abbiamo avuto un processo che ritenevamo idempotente, ma alla fine abbiamo aggiunto 2 valori x al giorno alla seconda esecuzione:

{ "_id" : "1", "type":"x", "value":1.23, date : ISODate("2013-05-21T08:00:00Z")}
{ "_id" : "2", "type":"x", "value":1.23, date : ISODate("2013-05-21T17:00:00Z")}

Abbiamo solo bisogno di 1 dei 2 record, quindi abbiamo dovuto ricorrere al javascript per ripulire il db. Il nostro approccio iniziale consisteva nell'iterare i risultati e rimuovere qualsiasi campo con un orario compreso tra le 6 e le 11 (tutti i duplicati erano in mattinata), ma durante l'implementazione ha apportato una modifica. Ecco lo script utilizzato per risolverlo:

var data = db.data.find({"type" : "x"})
var found = [];
while (data.hasNext()){
    var datum = data.next();
    var rdate = datum.date;
    // instead of the next set of conditions, we could have just used rdate.getHour() and checked if it was in the morning, but this approach was slightly better...
    if (typeof found[rdate.getDate()+"-"+rdate.getMonth() + "-" + rdate.getFullYear()] !== "undefined") {
       if (datum.value != found[rdate.getDate()+"-"+rdate.getMonth() + "-" + rdate.getFullYear()]) {
           print("DISCREPENCY!!!: " + datum._id + " for date " + datum.date);
       }
       else {
           print("Removing " + datum._id);
           db.data.remove({ "_id": datum._id});
       }
    }
    else {
       found[rdate.getDate()+"-"+rdate.getMonth() + "-" + rdate.getFullYear()] = datum.value;
    }
}

e poi lo ha eseguito con mongo thedatabase fixer_script.js

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.