Consulta do MongoDB / Mongoose em uma data específica?

141

É possível consultar uma data específica?

Eu descobri no mongo Cookbook que podemos fazer isso para um intervalo de consultas para um intervalo de datas assim:

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

Mas é possível para uma data específica? Isso não funciona:

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

Respostas:

211

Isso deve funcionar se as datas salvas no banco de dados estiverem sem tempo (apenas ano, mês, dia).

As chances são de que as datas que você salvou foram new Date(), o que inclui os componentes de horário. Para consultar esses horários, você precisa criar um período que inclua todos os momentos do dia.

db.posts.find( //query today up to tonight
  {"created_on": {"$gte": new Date(2012, 7, 14), "$lt": new Date(2012, 7, 15)}})
rdrey
fonte
29
Lembre-se que que na função Date (), o argumento mês começa a contagem em 0, não 1. Por outro lado, os dias iniciar a contagem em 1 ... detalhes
Mark Stosberg
não é melhor fazer _ 1 dia para obter a próxima data, em vez de codificar os dois?
raju
2
Esse método funciona bem se a data for armazenada da seguinte maneira: >> "date": ISODate ("2016-01-04T14: 07: 17.496Z")
santhosh
Você não tem seus meses e datas? O formato das datas deve ser: aaaa, dd, MM
thethakuri 2/16
123

... 5+ anos mais tarde, eu sugiro fortemente usando data-FNS vez

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

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

Para aqueles que usam o Moment.js

const moment = require('moment')

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

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

Importante: todos os momentos são mutáveis !

tomorrow = today.add(1, 'days')não funciona, pois também sofre mutação today. A chamada moment(today)resolve esse problema clonando implicitamente today.

Pier-Luc Gendreau
fonte
13
Sugiro usar em .startOf('day')vez de .horas (0) .minutos (0) .segundos (0). Portanto, a primeira linha seria:var today = moment().startOf('day')
Jim Geurts
2
Se estamos usando moment(today)para clonar o objeto, outra solução é:var tomorrow = today.clone().add(1, 'days')
johntellsall
1
@johntellsall Clonagem explícita e não implícita, mesmo resultado, mas talvez seja mais fácil de ler!
Pier-Luc Gendreau
1
Como alternativa, eu poderia sugerir o seguinte para $lt: moment(today).endOf('day'). Para impedir que os resultados reais sejam incluídos no dia seguinte.
22618 greduan
1
para mim moment(today).endOf('day')dá no mesmo dia com o tempo de: 23:59:59.999. Então, na verdade, parece mais correto de usar $lte, caso contrário, os objetos naquele momento específico serão ignorados.
Leonprou
11

Sim, o objeto Date cumpre a data e a hora, portanto, compará-lo com apenas o valor da data não funciona.

Você pode simplesmente usar o operador $ where para expressar uma condição mais complexa com a expressão booleana Javascript :)

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

created_on é o campo datetime e 2012-07-14 é a data especificada.

A data deve estar exatamente no formato AAAA-MM-DD .

Nota: Use $wherecom moderação, tem implicações no desempenho.

Faisal Hasnain
fonte
10

Você tentou:

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

O problema que você encontrará é que as datas são armazenadas como carimbos de data e hora no Mongo. Portanto, para corresponder a uma data, você está pedindo que corresponda a um carimbo de data e hora. No seu caso, acho que você está tentando combinar um dia (por exemplo, das 00:00 às 23:59 em uma data específica). Se suas datas são armazenadas sem horários, você deve ficar bem. Caso contrário, tente especificar sua data como um intervalo de tempo no mesmo dia (por exemplo, start = 00: 00, end = 23: 59) se o gte não funcionar.

pergunta semelhante

Michael D Johnson
fonte
1
Isso incluirá todos os elementos menores que a data especificada, o que provavelmente não é o que o OP queria. Considere adicionar uma opção "lt" como as outras respostas.
BenSower
Eu acho que se você tiver, em $gtevez disso gte, seria melhor.
tomada em branco
Isso já foi respondido mais corretamente acima, mas estava me incomodando por saber que minha resposta estava desativada, então atualizei-a para estar correta para a pergunta. Ei, já faz 4 anos. lol
Michael D Johnson
6

Você pode usar a seguinte abordagem para o método API para obter resultados de um dia específico:

# [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
fonte
1

Tivemos um problema relacionado a dados duplicados em nosso banco de dados, com um campo de data com vários valores nos quais deveríamos ter 1. Pensei em adicionar a maneira como resolvemos o problema para referência.

Temos uma coleção chamada "dados" com um campo numérico "valor" e um campo de data "data". Tivemos um processo que julgamos idempotente, mas acabamos adicionando 2 x valores por dia na segunda execução:

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

Precisamos apenas de 1 dos 2 registros, portanto tivemos que recorrer ao javascript para limpar o banco de dados. Nossa abordagem inicial seria iterar os resultados e remover qualquer campo com um tempo entre 6h e 11h (todas as duplicatas eram pela manhã), mas durante a implementação, fizemos uma alteração. Aqui está o script usado para corrigi-lo:

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 depois rodou com mongo thedatabase fixer_script.js

Brett
fonte