Zapytania MongoDB / Mongoose w określonym dniu?

141

Czy można zapytać o konkretną datę?

W książce kucharskiej mongo znalazłem, że możemy to zrobić dla zapytania o zakres dat w następujący sposób :

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

Ale czy jest to możliwe na konkretną datę? To nie działa:

db.posts.find({"created_on": new Date(2012, 7, 14) })
Unitech
źródło

Odpowiedzi:

212

To powinno działać, jeśli daty zapisane w bazie danych są bez czasu (tylko rok, miesiąc, dzień).

Możliwe, że zapisałeś daty new Date(), które obejmują składniki czasu. Aby sprawdzić te czasy, musisz utworzyć zakres dat obejmujący wszystkie momenty w ciągu dnia.

db.posts.find( //query today up to tonight
  {"created_on": {"$gte": new Date(2012, 7, 14), "$lt": new Date(2012, 7, 15)}})
rdrey
źródło
29
Pamiętaj, że w funkcji Date () argument miesiąc zaczyna liczyć od 0, a nie od 1. Z drugiej strony, dni liczone są od 1 ... szczegóły
Mark Stosberg
czy nie lepiej jest zrobić _ 1 dzień, aby uzyskać następną datę, zamiast na stałe zakodować oba z nich?
raju
2
Czy ta metoda działa dobrze, jeśli data jest przechowywana w następujący sposób: >> "date": ISODate ("2016-01-04T14: 07: 17.496Z")
santhosh
Nie masz swoich miesięcy i zmian daty. Format dat powinien być następujący: yyyy, dd, MM
thethakuri
123

... 5+ lat później zdecydowanie sugeruję użycie zamiast tego date-fns

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

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

Dla tych z nas, którzy używają Moment.js.

const moment = require('moment')

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

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

Ważne: wszystkie momenty są zmienne !

tomorrow = today.add(1, 'days')nie działa, ponieważ również mutuje today. Wywołanie moment(today)rozwiązuje ten problem przez niejawne klonowanie today.

Pier-Luc Gendreau
źródło
13
Sugeruję użycie .startOf('day')zamiast .hours (0) .minutes (0) .seconds (0). Tak więc pierwsza linia var today = moment().startOf('day')
brzmiałaby
2
Jeśli używamy moment(today)do klonowania obiektu, innym rozwiązaniem jest:var tomorrow = today.clone().add(1, 'days')
johntellsall
1
@johntellsall Klonowanie jawne zamiast niejawnego, ten sam wynik, ale być może rzeczywiście łatwiejszy do odczytania!
Pier-Luc Gendreau
1
Ewentualnie mogę zaproponować następujące zalecenia $lt: moment(today).endOf('day'). Aby zapobiec uwzględnieniu rzeczywistych wyników z następnego dnia.
greduan
1
mi moment(today).endOf('day')daje ten sam dzień z czasów: 23:59:59.999. W rzeczywistości wygląda to bardziej poprawnie w użyciu $lte, w przeciwnym razie obiekty w tym konkretnym czasie zostaną zignorowane.
leonprou,
11

Tak, obiekt Date uzupełnia datę i godzinę, więc porównywanie go tylko z wartością daty nie działa.

Możesz po prostu użyć operatora $ where , aby wyrazić bardziej złożony warunek za pomocą wyrażenia logicznego JavaScript :)

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

created_onjest polem 2012-07-14daty i godziny i jest określoną datą.

Data powinna być dokładnie w formacie RRRR-MM-DD .

Uwaga: używaj $whereoszczędnie, ma to wpływ na wydajność.

Faisal Hasnain
źródło
10

Czy próbowałeś:

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

Problem, z którym się spotkasz, polega na tym, że daty są przechowywane jako znaczniki czasu w Mongo. Tak więc, aby dopasować datę, chcesz, aby pasowała do znacznika czasu. W twoim przypadku myślę, że próbujesz dopasować dzień (tj. Od 00:00 do 23:59 w określonym dniu). Jeśli twoje daty są przechowywane bez czasu, powinieneś być w porządku. W przeciwnym razie spróbuj określić datę jako zakres czasu tego samego dnia (np. Start = 00: 00, koniec = 23: 59), jeśli gte nie działa.

podobne pytanie

Michael D. Johnson
źródło
1
Obejmuje to wszystkie elementy młodsze niż określona data, co prawdopodobnie nie jest tym, czego chciał OP. Rozważ dodanie opcji „lt”, takiej jak inne odpowiedzi.
BenSower
Myślę, że gdybyś miał $gtezamiast tego gte, byłoby lepiej.
gniazdo jack puste
Na to odpowiedź została już poprawiona powyżej, ale przeszkadzała mi świadomość, że moja odpowiedź jest wyłączona, więc zaktualizowałem ją, aby była poprawna dla pytania. Hej, to już 4 lata. lol
Michael D Johnson
6

Możesz zastosować następujące podejście do metody API, aby uzyskać wyniki z określonego dnia:

# [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
źródło
1

Mieliśmy problem ze zduplikowanymi danymi w naszej bazie danych, z polem daty zawierającym wiele wartości, w których mieliśmy mieć 1. Pomyślałem, że dodam sposób, w jaki rozwiązaliśmy ten problem w celach informacyjnych.

Mamy zbiór o nazwie „dane” z polem numerycznym „wartość” i polem „data”. Mieliśmy proces, który uważaliśmy za idempotentny, ale ostatecznie dodaliśmy 2 x wartości dziennie przy drugim uruchomieniu:

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

Potrzebujemy tylko 1 z 2 rekordów, więc musieliśmy skorzystać z javascript, aby wyczyścić bazę danych. Nasze początkowe podejście polegało na iteracji wyników i usunięciu dowolnego pola z czasem między 6 rano a 11 rano (wszystkie duplikaty były rano), ale podczas wdrażania wprowadzono zmianę. Oto skrypt użyty do rozwiązania tego problemu:

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

a następnie uruchomiłem go z mongo thedatabase fixer_script.js

Brett
źródło