MongoDB / Mongoose zu einem bestimmten Datum abfragen?

141

Ist es möglich, ein bestimmtes Datum abzufragen?

Ich fand in dem Mongo - Kochbuch , dass wir es für einen Bereich tun können Querying für einen Datumsbereich wie folgt aus:

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

Aber ist es für ein bestimmtes Datum möglich? Das funktioniert nicht:

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

Antworten:

210

Das sollte funktionieren, wenn die Daten, die Sie in der Datenbank gespeichert haben, keine Zeit haben (nur Jahr, Monat, Tag).

Möglicherweise waren die von Ihnen gespeicherten Daten new Date(), einschließlich der Zeitkomponenten. Um diese Zeiten abzufragen, müssen Sie einen Datumsbereich erstellen, der alle Momente eines Tages umfasst.

db.posts.find( //query today up to tonight
  {"created_on": {"$gte": new Date(2012, 7, 14), "$lt": new Date(2012, 7, 15)}})
rdrey
quelle
28
Denken Sie daran, dass in der Funktion Date () das Argument month bei 0 und nicht bei 1 beginnt. Andererseits zählen die Tage bei 1 ... details
Mark Stosberg
Ist es nicht besser, _ 1 Tag zu tun, um das nächste Datum zu erhalten, als beide hart zu codieren?
Raju
2
Funktioniert diese Methode einwandfrei, wenn das Datum wie folgt gespeichert wird: >> "Datum": ISODate ("2016-01-04T14: 07: 17.496Z")
Santhosh
Haben Sie nicht Ihre Monate und Datumswechsel. Datumsformat sollte sein: JJJJ, TT, MM
Thethakuri
123

... 5+ Jahre später empfehle ich dringend, stattdessen date-fns zu verwenden

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

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

Für diejenigen von uns, die Moment.js verwenden

const moment = require('moment')

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

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

Wichtig: Alle Momente sind veränderlich !

tomorrow = today.add(1, 'days')funktioniert nicht, da es auch mutiert today. Das Aufrufen moment(today)löst dieses Problem durch implizites Klonen today.

Pier-Luc Gendreau
quelle
13
Ich schlage vor, .startOf('day')anstelle von .hours (0) .minutes (0) .seconds (0) zu verwenden. Die erste Zeile wäre also:var today = moment().startOf('day')
Jim Geurts
2
Wenn wir verwenden moment(today), um das Objekt zu klonen, ist eine andere Lösung:var tomorrow = today.clone().add(1, 'days')
johntellsall
1
@johntellsall Explizites Klonen statt implizites, gleiches Ergebnis, aber vielleicht tatsächlich leichter zu lesen!
Pier-Luc Gendreau
1
Alternativ könnte ich Folgendes vorschlagen für $lt: moment(today).endOf('day'). Um zu verhindern, dass tatsächliche Ergebnisse vom nächsten Tag aufgenommen werden.
Greduan
1
für mich moment(today).endOf('day')gibt der gleiche Tag mit der Zeit von : 23:59:59.999. Sieht also tatsächlich korrekter aus $lte, da sonst Objekte zu diesem bestimmten Zeitpunkt ignoriert werden.
Leonprou
11

Ja, das Datumsobjekt erfasst Datum und Uhrzeit, sodass ein Vergleich mit nur dem Datumswert nicht funktioniert.

Sie können einfach den Operator $ where verwenden , um eine komplexere Bedingung mit einem booleschen Javascript-Ausdruck auszudrücken :)

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

created_onist das Datum / Uhrzeit-Feld und 2012-07-14ist das angegebene Datum.

Das Datum sollte genau im Format JJJJ-MM-TT vorliegen.

Hinweis: Verwenden Sie $wheresparsam, es hat Auswirkungen auf die Leistung.

Faisal Hasnain
quelle
10

Hast du es versucht:

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

Das Problem, auf das Sie stoßen werden, ist, dass Datumsangaben in Mongo als Zeitstempel gespeichert werden. Um also mit einem Datum übereinzustimmen, bitten Sie es, mit einem Zeitstempel übereinzustimmen. In Ihrem Fall denke ich, dass Sie versuchen, einen Tag abzugleichen (dh von 00:00 bis 23:59 an einem bestimmten Datum). Wenn Ihre Daten ohne Zeiten gespeichert sind, sollten Sie in Ordnung sein. Versuchen Sie andernfalls, Ihr Datum als Zeitbereich am selben Tag anzugeben (dh Start = 00: 00, Ende = 23: 59), wenn gte nicht funktioniert.

ähnliche Frage

Michael D Johnson
quelle
1
Dies schließt alle Elemente ein, die jünger als das angegebene Datum sind, was wahrscheinlich nicht das ist, was OP wollte. Erwägen Sie das Hinzufügen einer "lt" -Option wie die anderen Antworten.
BenSower
Ich denke, wenn Sie $gtestattdessen haben gte, wäre es besser.
Jack Blank
Dies wurde oben bereits korrekter beantwortet, aber es nervte mich zu wissen, dass meine Antwort nicht stimmte, und ich habe sie aktualisiert, um sie für die Frage korrekt zu machen. Hey, es ist 4 Jahre her. lol
Michael D Johnson
6

Sie können den folgenden Ansatz für die API-Methode verwenden, um Ergebnisse von einem bestimmten Tag zu erhalten:

# [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'
Daniel Kmak
quelle
1

Wir hatten ein Problem mit doppelten Daten in unserer Datenbank, mit einem Datumsfeld mit mehreren Werten, bei denen wir 1 haben sollten. Ich dachte, ich würde die Art und Weise hinzufügen, wie wir das Problem als Referenz gelöst haben.

Wir haben eine Sammlung namens "Daten" mit einem numerischen Feld "Wert" und einem Feld "Datum" Datum. Wir hatten einen Prozess, den wir für idempotent hielten, der jedoch beim zweiten Durchlauf 2 x Werte pro Tag hinzufügte:

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

Wir brauchen nur einen der beiden Datensätze, mussten also das Javascript verwenden, um die Datenbank zu bereinigen. Unser ursprünglicher Ansatz bestand darin, die Ergebnisse zu durchlaufen und alle Felder mit einer Zeit zwischen 6 und 11 Uhr zu entfernen (alle Duplikate waren am Morgen), aber während der Implementierung eine Änderung vorzunehmen. Hier ist das Skript, mit dem das Problem behoben wurde:

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

und dann lief es mit mongo thedatabase fixer_script.js

Brett
quelle