MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Trouver le dernier enregistrement de chaque jour

Un peu plus moderne que la réponse d'origine :

db.collection.aggregate([
  { "$sort": { "date": 1 } },
  { "$group": {
    "_id": {
      "$subtract": ["$date",{"$mod": ["$date",86400000]}]
    },
    "doc": { "$last": "$$ROOT" }
  }},
  { "$replaceRoot": { "newDocument": "$doc" } }
])

Le même principe s'applique que vous $sort la collection puis $group sur la clé de regroupement requise en récupérant le $last données de la limite de regroupement.

Pour rendre les choses un peu plus claires depuis l'écriture originale, vous pouvez utiliser $$ROOT au lieu de spécifier chaque propriété de document, et bien sûr le $replaceRoot vous permet de restaurer entièrement ces données sous la forme du document d'origine.

Mais la solution générale est toujours $sort d'abord, puis $group sur la clé commune requise et conservez le $last ou $first en fonction des occurrences de l'ordre de tri à partir de la limite de regroupement pour les propriétés requises.

Également pour les dates BSON par opposition à une valeur d'horodatage comme dans la question, voir Regrouper le résultat par intervalle de temps de 15 minutes dans MongoDb pour différentes approches sur la façon d'accumuler pour différents intervalles de temps en utilisant et en renvoyant des valeurs de date BSON.

Je ne sais pas trop ce que vous recherchez ici, mais vous pouvez le faire globalement si ma compréhension est bonne. Donc, pour obtenir le dernier enregistrement pour chaque jour :

db.collection.aggregate([
    // Sort in date order  as ascending
    {"$sort": { "date": 1 } },

    // Date math converts to whole day
    {"$project": {
        "adco": 1,
        "hchc": 1,
        "hchp": 1,
        "hhphc": 1,
        "ptec": 1,
        "iinst": 1,
        "papp": 1,
        "imax": 1,
        "optarif": 1,
        "isousc": 1,
        "motdetat": 1,
        "date": 1,
        "wholeDay": {"$subtract": ["$date",{"$mod": ["$date",86400000]}]} 
    }},

    // Group on wholeDay ( _id insertion is monotonic )
    {"$group": 
        "_id": "$wholeDay",
        "docId": {"$last": "$_id" },
        "adco": {"$last": "$adco" },
        "hchc": {"$last": "$hchc" },
        "hchp": {"$last": "$hchp" },
        "hhphc": {"$last": "$hhphc" },
        "ptec": {"$last": "$ptec" },
        "iinst": {"$last": "$iinst" },
        "papp": {"$last": "$papp" },
        "imax": {"$last": "$imax" },
        "optarif": {"$last": "$optarif",
        "isousc": {"$last": "$isouc" },
        "motdetat": {"$last": "$motdetat" },
        "date": {"$last": "$date" },
    }}
])

Donc, le principe ici est que, compte tenu de la valeur de l'horodatage, faites le calcul de la date pour projeter cela comme l'heure de minuit au début de chaque journée. Puis comme _id la clé sur le document est déjà monotone (toujours croissante), alors il suffit de grouper sur le wholeDay value tout en tirant le $last document à partir de la limite de regroupement.

Si vous n'avez pas besoin de tous les champs, projetez et regroupez uniquement ceux que vous voulez.

Et oui, vous pouvez le faire dans le cadre de données de printemps. Je suis sûr qu'il y a une commande enveloppée là-dedans. Mais sinon, l'incantation pour accéder à la commande native ressemble à ceci :

mongoOps.getCollection("yourCollection").aggregate( ... )

Pour mémoire, si vous aviez réellement des types de date BSON plutôt qu'un horodatage en tant que nombre, vous pouvez ignorer le calcul de la date :

db.collection.aggregate([
    { "$group": { 
        "_id": { 
            "year": { "$year": "$date" },
            "month": { "$month": "$date" },
            "day": { "$dayOfMonth": "$date" }
        },
        "hchp": { "$last": "$hchp" }
    }}
])