MongoDB / Mongoose interrogant à une date précise?

141

Est-il possible de demander une date précise?

J'ai trouvé dans le livre de recettes mongo que nous pouvons le faire pour une plage Interrogation d'une plage de dates comme celle-ci:

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

Mais est-ce possible pour une date précise? Cela ne fonctionne pas:

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

Réponses:

213

Cela devrait fonctionner si les dates que vous avez enregistrées dans la base de données sont sans heure (juste année, mois, jour).

Il y a de fortes chances que les dates que vous avez enregistrées l'étaient new Date(), ce qui inclut les composants de temps. Pour interroger ces heures, vous devez créer une plage de dates qui inclut tous les moments d'une journée.

db.posts.find( //query today up to tonight
  {"created_on": {"$gte": new Date(2012, 7, 14), "$lt": new Date(2012, 7, 15)}})
rdrey
la source
29
Rappelez-vous que dans la fonction Date (), l'argument du mois commence à compter à 0, et non à 1. Par contre, les jours commencent à compter à 1 ... détails
Mark Stosberg
N'est-il pas préférable de faire _ 1 jour pour obtenir la prochaine date plutôt que de coder les deux en dur?
raju
2
Cette méthode fonctionne-t-elle bien si la date est stockée comme ceci: >> "date": ISODate ("2016-01-04T14: 07: 17.496Z")
santhosh
N'avez-vous pas vos mois et dates. Le format des dates doit être: aaaa, jj, MM
thethakuri
124

... 5+ ans plus tard, je suggère fortement d'utiliser les date-fns à la place

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

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

Pour ceux d'entre nous qui utilisent Moment.js

const moment = require('moment')

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

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

Important: tous les moments sont mutables !

tomorrow = today.add(1, 'days')ne fonctionne pas car il mute également today. L'appel moment(today)résout ce problème en clonant implicitement today.

Pier-Luc Gendreau
la source
14
Je suggère d'utiliser .startOf('day')au lieu de .hours (0) .minutes (0) .seconds (0). La première ligne serait donc:var today = moment().startOf('day')
Jim Geurts
2
Si nous utilisons moment(today)pour cloner l'objet, une autre solution est:var tomorrow = today.clone().add(1, 'days')
johntellsall
1
@johntellsall Clonage explicite plutôt qu'implicite, même résultat mais peut-être plus facile à lire!
Pier-Luc Gendreau
1
Sinon, je pourrais suggérer ce qui suit pour $lt: moment(today).endOf('day'). Pour éviter que les résultats réels du lendemain ne soient inclus.
greduan le
1
pour moi moment(today).endOf('day')donne le même jour avec le temps de: 23:59:59.999. Cela semble donc plus correct à utiliser $lte, sinon les objets à ce moment-là seront ignorés.
leonprou
11

Ouais, l'objet Date complète la date et l'heure, donc le comparer avec la valeur de date uniquement ne fonctionne pas.

Vous pouvez simplement utiliser l' opérateur $ where pour exprimer une condition plus complexe avec une expression booléenne Javascript :)

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

created_on est le champ datetime et 2012-07-14 est la date spécifiée.

La date doit être exactement au format AAAA-MM-JJ .

Remarque: à utiliser $whereavec parcimonie, cela a des implications sur les performances.

Faisal Hasnain
la source
10

As-tu essayé:

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

Le problème que vous allez rencontrer est que les dates sont stockées sous forme d'horodatages dans Mongo. Donc, pour correspondre à une date, vous lui demandez de correspondre à un horodatage. Dans votre cas, je pense que vous essayez de faire correspondre un jour (c'est-à-dire de 00h00 à 23h59 à une date précise). Si vos dates sont stockées sans heure, vous devriez être d'accord. Sinon, essayez de spécifier votre date sous forme de plage horaire le même jour (par exemple, début = 00: 00, fin = 23: 59) si gte ne fonctionne pas.

question similaire

Michael D Johnson
la source
1
Cela inclura tous les éléments plus jeunes que la date spécifiée, ce qui n'est probablement pas ce que OP voulait. Pensez à ajouter une option "lt" comme les autres réponses.
BenSower
Je pense que si vous avez $gteau lieu de gtecela, ce serait mieux.
jack blank
Cela a déjà été répondu plus correctement ci-dessus, mais cela me dérangeait de savoir que ma réponse était désactivée, alors je l'ai mise à jour pour qu'elle corresponde à la question. Hé, ça fait 4 ans. lol
Michael D Johnson
6

Vous pouvez utiliser l'approche suivante pour la méthode API pour obtenir des résultats d'un jour spécifique:

# [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
la source
1

Nous avons eu un problème lié aux données dupliquées dans notre base de données, avec un champ de date ayant plusieurs valeurs là où nous étions censés avoir 1. J'ai pensé ajouter la façon dont nous avons résolu le problème pour référence.

Nous avons une collection appelée "data" avec un champ numérique "value" et un champ date "date". Nous avons eu un processus que nous pensions idempotent, mais nous avons fini par ajouter 2 x valeurs par jour lors de la deuxième exécution:

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

Nous n'avons besoin que de 1 des 2 enregistrements, nous avons donc dû recourir au javascript pour nettoyer la base de données. Notre approche initiale allait consister à parcourir les résultats et à supprimer tout champ avec un temps compris entre 6h et 11h (tous les doublons étaient le matin), mais lors de la mise en œuvre, nous avons fait un changement. Voici le script utilisé pour résoudre ce problème:

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

et puis l'a couru avec mongo thedatabase fixer_script.js

Brett
la source