MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Finden Sie die letzte Aufzeichnung eines jeden Tages

Etwas moderner als die ursprüngliche Antwort:

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

Es gilt das gleiche Prinzip, dass Sie im Wesentlichen $sort die Sammlung und dann $group auf dem erforderlichen Gruppierungsschlüssel, indem Sie den $last Daten von der Gruppierungsgrenze.

Um die Dinge etwas klarer zu machen, da die ursprüngliche Schreibweise darin besteht, dass Sie $$ROOT verwenden können Anstatt jede Dokumenteigenschaft anzugeben, und natürlich $replaceRoot stage ermöglicht es Ihnen, diese Daten vollständig als Originaldokumentform wiederherzustellen.

Aber die allgemeine Lösung ist immer noch $sort zuerst, dann $group auf dem erforderlichen gemeinsamen Schlüssel und behalten Sie den $last oder $first je nach Vorkommnissen der Sortierreihenfolge von der Gruppierungsgrenze für die erforderlichen Eigenschaften.

Auch für BSON-Daten im Gegensatz zu einem Zeitstempelwert wie in der Frage siehe Gruppenergebnis nach 15-Minuten-Zeitintervall in MongoDb für verschiedene Ansätze, wie man für verschiedene Zeitintervalle tatsächlich BSON-Datumswerte verwendet und zurückgibt.

Ich bin mir nicht ganz sicher, worauf Sie hier hinaus wollen, aber Sie könnten dies insgesamt tun, wenn mein Verständnis richtig ist. So erhalten Sie den letzten Datensatz für jeden Tag:

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" },
    }}
])

Das Prinzip hier ist also, dass angesichts des Zeitstempelwerts die Datumsberechnung durchgeführt wird, um dies als Mitternachtszeit am Anfang jedes Tages zu projizieren. Dann als _id Schlüssel auf dem Dokument ist bereits monoton (immer steigend), dann gruppieren Sie einfach auf den ganztägig Wert beim Ziehen von $last Dokument von der Gruppierungsgrenze.

Wenn Sie nicht alle Felder benötigen, projizieren und gruppieren Sie nur die gewünschten Felder.

Und ja, Sie können dies im Spring Data Framework tun. Ich bin mir sicher, dass dort ein umschlossener Befehl enthalten ist. Aber ansonsten lautet die Beschwörung, um zum nativen Befehl zu gelangen, etwa so:

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

Für die Aufzeichnung, wenn Sie tatsächlich BSON-Datumstypen anstelle eines Zeitstempels als Zahl hatten, können Sie die Datumsberechnung überspringen:

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