sql >> Base de Datos >  >> NoSQL >> MongoDB

Encuentra el último registro de cada día

Un poco más moderno que la respuesta original:

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

Se aplica el mismo principio que esencialmente $sort la colección y luego $group en la clave de agrupación requerida seleccionando $last datos del límite de agrupación.

Haciendo las cosas un poco más claras ya que la escritura original es que puedes usar $$ROOT en lugar de especificar cada propiedad del documento y, por supuesto, el $replaceRoot etapa le permite restaurar esos datos completamente como el formulario del documento original.

Pero la solución general sigue siendo $sort primero, luego $group en la clave común que se requiere y mantenga el $last o $first dependiendo de las ocurrencias del orden de clasificación desde el límite de agrupación para las propiedades que se requieren.

También para fechas BSON en lugar de un valor de marca de tiempo como en la pregunta, consulte Resultado de grupo por intervalo de tiempo de 15 minutos en MongoDB para diferentes enfoques sobre cómo acumular para diferentes intervalos de tiempo utilizando y devolviendo valores de fecha BSON.

No estoy muy seguro de lo que está buscando aquí, pero podría hacer esto en conjunto si mi entendimiento es correcto. Entonces, para obtener el último registro de cada día:

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

Entonces, el principio aquí es que, dado el valor de la marca de tiempo, haga las matemáticas de la fecha para proyectarlo como la medianoche al comienzo de cada día. Luego como el _id clave en el documento ya es monótona (siempre creciente), luego simplemente agrupe en el wholeDay valor mientras extrae el $last documento del límite de agrupación.

Si no necesita todos los campos, solo proyecte y agrupe los que desee.

Y sí, puede hacer esto en el marco de datos de primavera. Estoy seguro de que hay un comando envuelto allí. Pero por lo demás, el conjuro para llegar al comando nativo es algo así:

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

Para que conste, si realmente tenía tipos de fecha BSON en lugar de una marca de tiempo como un número, entonces puede omitir las matemáticas de fecha:

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