using MapoSDK; using MongoDB.Driver; using SteamWare; using System; using System.Collections.Generic; using System.Diagnostics; using System.Text; namespace MapoDb { /************************************************************** * Classe gestione FluxLog * * automaticamente gestisce dati su SqlServer / Redis (+recenti) * oppure su MongoDB (+ vecchi) * * rif x mongoDB * * rif x windows setup (abilitazione firewall, remote access, auth...) * * https://docs.mongodb.com/manual/tutorial/configure-windows-netsh-firewall/ * https://www.configserverfirewall.com/mongodb/mongodb-allow-remote-connections/ * https://www.shellhacks.com/mongodb-allow-remote-access/ * https://stackoverflow.com/questions/3891657/setup-mongodb-on-windows-server-2008 * * (conf file in C:\Program Files\MongoDB\Server\4.2\bin) * * * test rilettura: https://stackoverflow.com/questions/2943222/find-objects-between-two-dates-mongodb * https://studio3t.com/knowledge-base/articles/mongodb-find-method/ * https://github.com/mongodb/mongo-csharp-driver * http://www.binaryheap.com/tech/time-series-data-in-mongodb/ * https://www.codeproject.com/Tips/760099/Resampling-and-merging-time-series-data-using-LINQ * https://docs.microsoft.com/it-it/aspnet/core/tutorials/first-mongo-app?view=aspnetcore-3.0&tabs=visual-studio * https://www.codementor.io/pmbanugo/working-with-mongodb-in-net-1-basics-g4frivcvz * https://www.codementor.io/pmbanugo/working-with-mongodb-in-net-2-retrieving-mrlbeanm5 * https://www.codementor.io/pmbanugo/working-with-mongodb-in-net-part-3-skip-sort-limit-and-projections-oqfwncyka *************************************************************/ /// /// Classe che si occupa di gestire i dati di flusso /// - i dati inizialmente sono in REDIS e DB quando accumulati da IOB /// - successivamente i dati vengono archiviati come oggetti BSON in MongoDB /// public class FluxArchive { #if false string mdbConnString = "mongodb://W2019-MONGODB:27017"; //string mdbConnString = "mongodb://localhost:27017"; MongoClient client; #endif /// /// Database corrente MongoDB /// IMongoDatabase database; /// /// Classe gestione archivio allarmi /// public FluxArchive() { #if false // rifare avvio con lettura da web.config... client = new MongoClient(mdbConnString); database = client.GetDatabase("MAPO"); #endif database = memLayer.ML.getMongoDatabase("MAPO"); } public static FluxArchive man = new FluxArchive(); /// /// Effettua il trasferimento dati da SqlDB a MongoDB /// /// data di aprtenza /// num giorni da trasferire public exeResult trasferDataFromDb(DateTime data2transfer, int numDays) { exeResult answ = new exeResult(); StringBuilder sb = new StringBuilder(); Stopwatch sw = new Stopwatch(); DateTime tStamp; // oggetto gestione dati ts raggruppati var collRawData = database.GetCollection("FluxLogRawData"); var collHistData = database.GetCollection("FluxLogHistData"); var builderRaw = Builders.Filter; var builderHist = Builders.Filter; string currDateStr = ""; int startYMD = 0; int endYMD = 0; int currYMD = 0; // Effettuo eliminazione records x TUTTO il periodo dei dati RAW e stats... string startDateStr = data2transfer.ToString("yyyyMMdd"); string endDateStr = data2transfer.AddDays(numDays).ToString("yyyyMMdd"); int.TryParse(startDateStr, out startYMD); int.TryParse(endDateStr, out endYMD); // filtri e delete var filtRawOld = builderRaw.Gte(u => u.dateYMD, startYMD) & builderRaw.Lte(u => u.dateYMD, endYMD); collRawData.DeleteMany(filtRawOld); var filtHistOld = builderHist.Gte(u => u.dateYMD, startYMD) & builderHist.Lte(u => u.dateYMD, endYMD); collHistData.DeleteMany(filtHistOld); // faccio ciclo su OGNI macchina sw.Start(); var elencoMacchine = DataLayer.obj.taMacchine.GetData(); foreach (var macchina in elencoMacchine) { sb.AppendLine($"Inizio processing macchina {macchina.IdxMacchina}"); // faccio ciclo su gg richiesti... for (int i = 0; i < numDays; i++) { tStamp = data2transfer.AddDays(i); currDateStr = tStamp.ToString("yyyyMMdd"); int.TryParse(currDateStr, out currYMD); // leggo da DB i records... DS_applicazione.FluxLogDataTable tabDati = DataLayer.obj.taFL.getFiltOrd(macchina.IdxMacchina, tStamp, tStamp.AddDays(1), true); // solo se ho dati... if (tabDati.Count > 0) { // chiamo procedura x conversione List risultato = convertTable(tabDati, tStamp, timeWindow.day); // salvo in blocco if (risultato.Count > 0) { try { collRawData.InsertMany(risultato); // calcolo la NUOVA statistica giornaliera... var resStats = getStats(risultato); // salvo! collHistData.InsertOne(resStats); } catch (Exception exc) { } } sb.AppendLine($"DB {tStamp}: {tabDati.Count}rec | MongoDb {risultato.Count} RAW DOC in {sw.ElapsedMilliseconds / 1000} sec"); } } } // restituisco messaggio... answ.esito = esitoExec.ok; answ.message = sb.ToString(); return answ; } /// /// Converte una tabella dati da DB in una lista di oggetti pronti x salvataggio su MongoDb /// /// Tabelal dei dati RAW registrati /// Data di riferimento /// Periodo del campionamento desiderato (e passato coi dati che sono relativi a tale periodo...) public List convertTable(DS_applicazione.FluxLogDataTable tabDati, DateTime tStamp, timeWindow periodo) { // init oggetti List listaRecords = new List(); rawData currRecord = null; List valori = new List(); rawSample campione = null; string currFlux = ""; string currMacc = ""; string tStampString = tStamp.ToString("yyyyMMdd"); int tStampYMD = 0; int.TryParse(tStampString, out tStampYMD); foreach (var item in tabDati) { // controllo flusso x nuovo record... if (item.CodFlux != currFlux || item.IdxMacchina != currMacc) { // salvo il VECCHIO record... if (currRecord != null) { currRecord.samples = valori; listaRecords.Add(currRecord); valori = null; currRecord = null; } // nuovi record... currFlux = item.CodFlux; currMacc = item.IdxMacchina; valori = new List(); currRecord = new rawData() { macName = currMacc, varName = currFlux, varType = plcDataType.Real, // fare!!! dateYMD = tStampYMD, period = periodo }; } campione = new rawSample() { timeStamp = item.dtEvento, value = item.Valore }; // aggiunta sample ai record prec... if (campione != null && currRecord != null) { valori.Add(campione); campione = null; } } // aggiungo ultimo... salvo il VECCHIO record... if (currRecord != null) { currRecord.samples = valori; listaRecords.Add(currRecord); } return listaRecords; } /// /// Calcola statistiche per i dati giornalieri processati /// /// /// protected histData getStats(List datiGiornalieri) { // init oggetti histData currHist; varStats currStat; List statistiche = new List(); int sampleNumRec = 1; float sampleTotal = 0; float sampleMinVal = 0; float sampleMaxVal = 0; float sampleAvg = 0; float currVal = 0; bool fatto = false; string macName = ""; int dateYMD = 0; // ciclo x ogni variabile foreach (var item in datiGiornalieri) { if (item.samples != null) { if (string.IsNullOrEmpty(macName)) { macName = item.macName; dateYMD = item.dateYMD; } // reset vabiabili sampleTotal = 0; sampleMinVal = 0; sampleMaxVal = 0; sampleAvg = 0; // calcolo statistiche sampleNumRec = item.samples.Count; foreach (var sample in item.samples) { fatto = float.TryParse(sample.value, out currVal); if (fatto) { sampleTotal += currVal; sampleMaxVal = sampleMaxVal < currVal ? currVal : sampleMaxVal; sampleMinVal = sampleMinVal > currVal ? currVal : sampleMinVal; } } if (sampleNumRec > 0) { sampleAvg = sampleTotal / sampleNumRec; } // salvo statistica currStat = new varStats() { varName = item.varName, numRec = sampleNumRec, avg = sampleAvg, min = sampleMinVal, max = sampleMaxVal }; statistiche.Add(currStat); } } currHist = new histData() { macName = macName, varType = plcDataType.Real, dateYMD = dateYMD, period = timeWindow.day, stats = statistiche }; // restituisco... return currHist; } } }