531 votes

Recherche d'objets entre deux dates MongoDB

Je me suis amusé à stocker des tweets dans mongodb, chaque objet ressemble à ceci :

{
"_id" : ObjectId("4c02c58de500fe1be1000005"),
"contributors" : null,
"text" : "Hello world",
"user" : {
    "following" : null,
    "followers_count" : 5,
    "utc_offset" : null,
    "location" : "",
    "profile_text_color" : "000000",
    "friends_count" : 11,
    "profile_link_color" : "0000ff",
    "verified" : false,
    "protected" : false,
    "url" : null,
    "contributors_enabled" : false,
    "created_at" : "Sun May 30 18:47:06 +0000 2010",
    "geo_enabled" : false,
    "profile_sidebar_border_color" : "87bc44",
    "statuses_count" : 13,
    "favourites_count" : 0,
    "description" : "",
    "notifications" : null,
    "profile_background_tile" : false,
    "lang" : "en",
    "id" : 149978111,
    "time_zone" : null,
    "profile_sidebar_fill_color" : "e0ff92"
},
"geo" : null,
"coordinates" : null,
"in_reply_to_user_id" : 149183152,
"place" : null,
"created_at" : "Sun May 30 20:07:35 +0000 2010",
"source" : "web",
"in_reply_to_status_id" : {
    "floatApprox" : 15061797850
},
"truncated" : false,
"favorited" : false,
"id" : {
    "floatApprox" : 15061838001
}

Comment puis-je écrire une requête qui vérifie le *created_at* et trouve tous les objets entre 18:47 et 19:00 ? Dois-je mettre à jour mes documents pour que les dates soient stockées dans un format spécifique ?

Merci

0 votes

Vous ne dites pas sur quel champ vous voulez une requête ?

1 votes

Oups, je veux interroger le created_at et trouver tout entre deux dates.

0 votes

Je suis curieux de savoir pourquoi ne pas utiliser l'horodatage. Y a-t-il des avantages à utiliser l'objet Date ?

811voto

ponzao Points 7907

Recherche d'une plage de dates (mois ou jour spécifique) dans le Livre de recettes MongoDB a une très bonne explication sur le sujet, mais voici quelque chose que j'ai essayé moi-même et qui semble fonctionner.

items.save({
    name: "example",
    created_at: ISODate("2010-04-30T00:00:00.000Z")
})
items.find({
    created_at: {
        $gte: ISODate("2010-04-29T00:00:00.000Z"),
        $lt: ISODate("2010-05-01T00:00:00.000Z")
    }
})
=> { "_id" : ObjectId("4c0791e2b9ec877893f3363b"), "name" : "example", "created_at" : "Sun May 30 2010 00:00:00 GMT+0300 (EEST)" }

D'après mes expériences, vous devrez sérialiser vos dates dans un format pris en charge par MongoDB, car la méthode suivante donne des résultats de recherche indésirables.

items.save({
    name: "example",
    created_at: "Sun May 30 18.49:00 +0000 2010"
})
items.find({
    created_at: {
        $gte:"Mon May 30 18:47:00 +0000 2015",
        $lt: "Sun May 30 20:40:36 +0000 2010"
    }
})
=> { "_id" : ObjectId("4c079123b9ec877893f33638"), "name" : "example", "created_at" : "Sun May 30 18.49:00 +0000 2010" }

Dans le deuxième exemple, aucun résultat n'était attendu, mais il y avait quand même un obtenu. Cela est dû au fait qu'une comparaison de base entre chaînes de caractères est effectuée.

3 votes

Cela semble intéressant, mais la date enregistrée doit-elle être dans un format spécifique ? J'ai juste stocké ce qui était fourni par twitter, est-ce que cela doit être changé dans un format différent ?

9 votes

Vous avez probablement stocké les horodatages sous forme de chaînes, donc je suppose que MongoDB ne se rendra pas compte qu'il s'agit en fait de dates. Ainsi, si vous effectuez une requête de plage sur ces dates, vous obtiendrez une requête de plage alphabétique (par exemple, "Jan Mon 01.01.2010" avant "Jan Sun 01.01.1000"). Il serait probablement judicieux de formater toutes les données de date dans le format MongoDB, qui, je pense, est simplement JavaScript Date.

2 votes

Je viens de l'utiliser pour convertir mes chaînes de caractères en objets de date. stackoverflow.com/questions/2900674/

48voto

arcseldon Points 400

Pour clarifier. Ce qu'il est important de savoir, c'est que :

  • Oui, vous devez passer un objet Javascript Date.
  • Oui, il doit être compatible avec ISODate.
  • Oui, d'après mon expérience, pour que cela fonctionne, vous devez manipuler la date en ISO.
  • Oui, travailler avec des dates est généralement toujours un processus fastidieux, et mongo ne fait pas exception à la règle.

Voici un extrait de code fonctionnel, dans lequel nous effectuons une petite manipulation de la date pour nous assurer que Mongo (ici, j'utilise le module mongoose et je veux des résultats pour les lignes dont l'attribut date est inférieur à (avant) la date donnée comme paramètre myDate) peut le traiter correctement :

var inputDate = new Date(myDate.toISOString());
MyModel.find({
    'date': { $lte: inputDate }
})

1 votes

Plus un pour la clarté. Si vous utilisez moment dans le backend, il conserve la fonction toISOString(). J'utilise moment pour ajouter et soustraire du temps pour mes requêtes.

20voto

Ben Smith Points 552

MongoDB stocke en fait les millisecondes d'une date sous la forme d'un int(64), comme le prescrit la règle suivante http://bsonspec.org/#/specification

Cependant, cela peut devenir assez confus lorsque vous récupérez des dates, car le pilote client instancie un objet date avec son propre fuseau horaire local. Le pilote JavaScript dans la console mongo le fera certainement.

Donc, si vous tenez à vos fuseaux horaires, assurez-vous de savoir ce qu'il est censé être lorsque vous le récupérez. Cela ne devrait pas avoir trop d'importance pour les requêtes, puisque cela équivaudra toujours au même int(64), quel que soit le fuseau horaire dans lequel se trouve votre objet date (j'espère). Mais je ferais certainement des requêtes avec des objets date réels (pas des chaînes) et je laisserais le pilote faire son travail.

2voto

heregear Points 29

Convertissez vos dates en fuseau horaire GMT lorsque vous les introduisez dans Mongo. De cette façon, il n'y aura jamais de problème de fuseau horaire. Ensuite, il suffit de faire les calculs sur le champ twitter/timezone lorsque vous récupérez les données pour les présenter.

-1voto

ayu for u Points 10

J'ai essayé ce modèle en fonction de mes besoins, j'ai besoin de stocker une date quand un objet est créé, puis je veux récupérer tous les enregistrements (documents) entre deux dates. dans mon fichier html j'utilisais le format suivant mm/dd/yyyy

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>

    <script>
//jquery
    $(document).ready(function(){  
    $("#select_date").click(function() { 
    $.ajax({
    type: "post",
    url: "xxx", 
    datatype: "html",
    data: $("#period").serialize(),  
    success: function(data){
    alert(data);
    } ,//success

    }); //event triggered

    });//ajax
    });//jquery  
    </script>

    <title></title>
</head>

<body>
    <form id="period" name='period'>
        from <input id="selecteddate" name="selecteddate1" type="text"> to 
        <input id="select_date" type="button" value="selected">
    </form>
</body>
</html>

dans mon fichier py (python), je l'ai converti en "iso fomate". de la manière suivante

date_str1   = request.POST["SelectedDate1"] 
SelectedDate1   = datetime.datetime.strptime(date_str1, '%m/%d/%Y').isoformat()

et enregistré dans ma collection dbmongo avec "SelectedDate" comme champ dans ma collection.

pour récupérer des données ou des documents entre deux dates, j'ai utilisé la requête suivante

db.collection.find( "SelectedDate": {'$gte': SelectedDate1,'$lt': SelectedDate2}})

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X