2016-05-19 41 views
6

Sto avendo un set di dati che contiene punti dati ogni 5 secondi al giorno. Ciò comporterebbe un set di dati di articoli al giorno. Questo set è troppo grande e lo voglio più piccolo (sto usando questi elementi per disegnare un grafico).Symfony/Doctrine/MongoDB Ottieni ogni ennesimo elemento

Poiché l'asse x del grafico è nel tempo, ho deciso che una distanza di 5 minuti per punto di dati è sufficiente. Questo ritornerà nei datapoints al giorno. Molto meno e abbastanza buono per fare un grafico.

mio MongoCollection si presenta così:

{ 
    "timestamp":"12323455", 
    "someKey":123, 
    "someOtherKey": 345, 
    "someOtherOtherKey": 6789 
} 

I dati viene pubblicato ogni 5 secondi nel database. Quindi il timestamp differirà di 5 secondi per ogni risultato.

Poiché il mio asse x è diviso in sequenze di 5 minuti, mi piacerebbe calcolare i valori medi di someKey, someOtherKey e someOtherOtherkey in questi 5 minuti. Questa nuova media sarà uno dei punti dati nel mio grafico.

Come si possono ottenere tutti i datapoints da 1 giorno con una media di 5 minuti di distanza l'una dall'altra? (288 punti dati al giorno).

Per quanto riguarda ora sto selezionando ogni documento da mezzanotte di questo giorno:

$result = $collection 
    ->createQueryBuilder() 
    ->field('timestamp')->gte($todayMidnight) 
    ->sort('timestamp', 'DSC') 
    ->getQuery() 
    ->execute(); 

Come si potrebbe filtrare questo elenco di dati (all'interno della stessa query) per ottenere i datapoint per ogni 5 minuti (e la il datapoint è una media dei punti in questi 5 minuti)?

Sarebbe bello avere questa query creata con dottrina come ne avrò bisogno nella mia applicazione symfony.

EDIT Ho cercato di ottenere prima la mia query all'interno del funzionamento di mongoshell. Come nei commenti suggeriti, dovrei iniziare a usare aggregation.

L'interrogazione che ho fatto fino ad ora si basa su un'altra domanda posta qui a stackoverflow

Questa è la query corrente:

db.Pizza.aggregate([ 
    { 
     $match: 
     { 
      timestamp: {$gte: 1464559200} 
     } 
    }, 
    { 
     $group: 
     { 
      _id: 
      { 
       $subtract: [ 
        "$timestamp", 
        {"$mod": ["$timestamp", 300]} 
       ] 
      }, 
      "timestamp":{"$first":"$timestamp"}, 
      "someKey":{"$first":"$someKey"}, 
      "someOtherKey":{"$first":"$someOtherKey"}, 
      "someOtherOtherKey":{"$first":"$someOtherOtherKey"} 
     } 
    } 
]) 

Questa interrogazione mi darà l'ultimo risultato per ogni 300 secondi (5 minuti) da oggi a mezzanotte. Voglio che per ottenere tutti i documenti all'interno di quei 300 secondi e calcolare una media sopra le colonne someKey, someOtherKey, someOtherOtherKey

Quindi, se prendiamo questo esempio dataset:

{ 
    "timestamp":"1464559215", 
    "someKey":123, 
    "someOtherKey": 345, 
    "someOtherOtherKey": 6789 
}, 
{ 
    "timestamp":"1464559220", 
    "someKey":54, 
    "someOtherKey": 20, 
    "someOtherOtherKey": 511 
}, 
{ 
    "timestamp":"1464559225", 
    "someKey":654, 
    "someOtherKey": 10, 
    "someOtherOtherKey": 80 
}, 
{ 
    "timestamp":"1464559505", 
    "someKey":90, 
    "someOtherKey": 51, 
    "someOtherOtherKey": 1 
} 

La query deve restituire righe e cioè:

{ 
    "timestamp":"1464559225", 
    "someKey":277, 
    "someOtherKey": 125, 
    "someOtherOtherKey": 2460 
}, 
{ 
    "timestamp":"1464559505", 
    "someKey":90, 
    "someOtherKey": 51, 
    "someOtherOtherKey": 1 
} 

Il primo risultato viene calcolato in questo modo:

Result 1 - someKey = (123+54+654)/3 = 277 
Result 1 - someOtherKey = (345+20+10)/3 = 125 
Result 1 - someOtherOtherKey = (6789+511+80)/3 = 2460 

Come si può effettuare questo calcolo all'interno del mongoshell con la funzione di aggregazione?

+0

Sembra un lavoro per il framework di aggregazione, hai provato ad usarlo? – malarzm

+0

Come si usa la struttura di aggregazione? Ho provato a usare il gruppo ma mi sono bloccato:/ – Baklap4

+1

Non sono molto fluente con me stesso, probabilmente passerò attraverso la documentazione e altre domande su SO faranno luce :) Se si tratta di utilizzare l'aggregazione con Doctrine ODM non fornisce qualsiasi zucchero ancora (c'è un PR non finito per l'idratazione) ma è possibile usarlo. – malarzm

risposta

2

Sulla base delle risposte date qui su StackOverflow sono riuscito ad ottenere esattamente quello che volevo.

Questa è la grande domanda di aggregazione devo fare per ottenere tutti i miei risultati indietro:

parte
db.Pizza.aggregate([ 
    { 
     $match: 
     { 
      timestamp: {$gte: 1464559200} 
     } 
    }, 
    { 
     $group: 
     { 
      _id: 
      { 
       $subtract: [ 
        '$timestamp', 
        {$mod: ['$timestamp', 300]} 
       ] 
      }, 
      timestamp: {$last: '$timestamp'}, 
      someKey: {$avg: '$someKey'}, 
      someOtherKey: {$avg: '$someOtherKey'}, 
      someOtherOtherKey: {$avg: '$someOtherOtherKey'} 
     } 
    }, 
    { 
     $project: 
     { 
      _id: 0, 
      timestamp: '$timestamp', 
      someKey: '$someKey', 
      someOtherKey:'$someOtherKey', 
      someOtherOtherKey:'$someOtherOtherKey' 
     } 
    } 
]) 

Il Match è per ottenere ogni risultato dopo oggi Midnight (timestamp di oggi a mezzanotte).

La parte del gruppo è la parte più interessante. Qui eseguiamo il ciclo di ogni documento trovato e calcoliamo un modulo ogni 300 secondi (5 minuti), quindi riempiamo il timestamp della proprietà con l'ultimo risultato delle operazioni del modulo.

La parte Progetto è necessaria per rimuovere _id dal risultato effettivo in quanto il risultato non rappresenta più qualcosa nel database.

answeres Attribuite dove questo answere si basa su:

MongoDB - Aggregate max/min/average for multiple variables at once

How to subtract in mongodb php

MongoDB : Aggregation framework : Get last dated document per grouping ID

Dottrina Soluzione

$collection->aggregate([ 
    [ 
     '$match' => [ 
      'timestamp' => ['$gte' => 1464559200] 
     ] 
    ], 
    [ 
     '$group' => [ 
      '_id' => [ 
       '$subtract' => [ 
        '$timestamp', 
        [ 
         '$mod' => ['$timestamp',300] 
        ] 
       ] 
      ], 
      'timestamp' => [ 
       '$last' => '$timestamp' 
      ], 
      $someKey => [ 
       '$avg' => '$'.$someKey 
      ], 
      $someOtherKey => [ 
       '$avg' => '$'.$someOtherKey 
      ], 
      $someOtherOtherKey => [ 
       '$avg' => '$'.$someOtherOtherKey 
      ] 
     ] 
    ] 
]);