¿Consulta MongoDB / Mongoose en una fecha específica?

141

¿Es posible consultar una fecha específica?

En el Cookbook de mongo descubrí que podemos hacerlo para un rango Consultando un rango de fechas así:

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

¿Pero es posible para una fecha específica? Esto no funciona:

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

Respuestas:

211

Eso debería funcionar si las fechas que guardó en la base de datos no tienen tiempo (solo año, mes, día).

Lo más probable es que las fechas que guardó fueron new Date(), que incluye los componentes de tiempo. Para consultar esos horarios, debe crear un intervalo de fechas que incluya todos los momentos de un día.

db.posts.find( //query today up to tonight
  {"created_on": {"$gte": new Date(2012, 7, 14), "$lt": new Date(2012, 7, 15)}})
rdrey
fuente
29
Recuerde que en la función Fecha (), el argumento del mes comienza a contar en 0, no en 1. Por otro lado, los días comienzan a contar en 1 ... detalles
Mark Stosberg
¿no es mejor hacer _ 1 día para obtener la próxima fecha en lugar de codificar ambos?
raju
2
Este método funciona bien si la fecha se almacena así: >> "fecha": ISODate ("2016-01-04T14: 07: 17.496Z")
Sánto
No tienes tus meses y cambios de fecha. El formato de las fechas debe ser: aaaa, dd, MM
thethakuri
123

... más de 5 años más tarde, sugiero usar date-fns en su lugar

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

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

Para aquellos de nosotros que usamos 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 los momentos son mutables !

tomorrow = today.add(1, 'days')no funciona ya que también muta today. Llamar moment(today)resuelve ese problema al clonar implícitamente today.

Pier-Luc Gendreau
fuente
13
Sugiero usar en .startOf('day')lugar de .hours (0) .minutes (0) .seconds (0). Entonces la primera línea sería:var today = moment().startOf('day')
Jim Geurts
2
Si estamos usando moment(today)para clonar el objeto, otra solución es:var tomorrow = today.clone().add(1, 'days')
johntellsall
1
@johntellsall Clonación explícita en lugar de implícita, ¡el mismo resultado pero quizás más fácil de leer!
Pier-Luc Gendreau
1
Alternativamente, podría sugerir lo siguiente para $lt: moment(today).endOf('day'). Para evitar que se incluyan resultados reales del día siguiente.
greduan
1
me moment(today).endOf('day')da el mismo día con el momento de: 23:59:59.999. Por lo tanto, parece más correcto de usar $lte, de lo contrario, los objetos en ese momento en particular se ignorarán.
leonprou
11

Sí, el objeto Fecha completa la fecha y la hora, por lo que compararlo solo con el valor de la fecha no funciona.

Simplemente puede usar el operador $ where para expresar una condición más compleja con la expresión booleana de Javascript :)

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

created_ones el campo de fecha y hora y 2012-07-14es la fecha especificada.

La fecha debe estar exactamente en formato AAAA-MM-DD .

Nota: Use con $wheremoderación, tiene implicaciones de rendimiento.

Faisal Hasnain
fuente
10

Has probado:

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

El problema con el que se encontrará es que las fechas se almacenan como marcas de tiempo en Mongo. Entonces, para que coincida con una fecha, le está pidiendo que coincida con una marca de tiempo. En su caso, creo que está tratando de igualar un día (es decir, de 00:00 a 23:59 en una fecha específica). Si sus fechas se almacenan sin horarios, entonces debería estar bien. De lo contrario, intente especificar su fecha como un rango de tiempo en el mismo día (es decir, inicio = 00: 00, final = 23: 59) si gte no funciona.

pregunta similar

Michael D Johnson
fuente
1
Esto incluirá todos los elementos anteriores a la fecha especificada, que probablemente no sea lo que OP quería. Considere agregar una opción "lt" como las otras respuestas.
BenSower
Creo que si tienes en $gtelugar de gteeso sería mejor.
Jack en blanco el
Esto ya se ha respondido más correctamente anteriormente, pero me molestaba saber que mi respuesta estaba desactivada, así que la actualicé para que fuera correcta para la pregunta. Oye, han pasado 4 años. lol
Michael D Johnson
6

Puede usar el siguiente enfoque para el método API para obtener resultados de un día 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
fuente
1

Tuvimos un problema relacionado con los datos duplicados en nuestra base de datos, con un campo de fecha con múltiples valores donde debíamos tener 1. Pensé en agregar la forma en que resolvimos el problema como referencia.

Tenemos una colección llamada "datos" con un campo numérico de "valor" y un campo de fecha "fecha". Tuvimos un proceso que pensamos que era idempotente, pero terminamos agregando 2 valores por día en la segunda ejecución:

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

Solo necesitamos 1 de los 2 registros, por lo que tuvimos que recurrir al javascript para limpiar la base de datos. Nuestro enfoque inicial sería iterar a través de los resultados y eliminar cualquier campo con un tiempo entre las 6 a.m. y las 11 a.m. (todos los duplicados eran por la mañana), pero durante la implementación, se realizó un cambio. Aquí está la secuencia de comandos utilizada para solucionarlo:

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

y luego lo ejecuté con mongo thedatabase fixer_script.js

Brett
fuente