Я упомянул в комментарии об использовании периферийного устройства, которое позволяет назначить значение на соответствующий период. Используйте сервис nodeJS, чтобы выяснить, какой документ необходимо обновить, поскольку это делает запрос к коллекции намного проще и быстрее.
Вы можете использовать этот формат для каждого документа:
{
"period" : {
"start" : 1577836800,
"end" : 1577836820
},
"values": [
{
"value": 10
"timestamp": 1577836800
},
{
"value": 12
"timestamp": 1577836810
},
{
"value": 17
"timestamp": 1577836820
}
]
}
Как пример, когда датчик предоставляет сервису новое значение. В этом случае значение 2, получите последний документ и сравните его с последним значением в пределах значений.
если новое значение меньше предыдущего значения, создайте новый документ со следующей информацией и, конечно же, не забудьте обновить предыдущий документ, заполнив "periode.end" последним значением отметка времени.
{
"period" : {
"start" : 1577836830,
"end" : null
},
"values": [
{
"value": 2
"timestamp": 1577836830
}
]
}
ОБНОВЛЕНИЕ
Я написал этот сценарий JavaScript для миграции из одной коллекции, обработки данных в новом формате на основе требований и вставьте их в новую коллекцию.
function createSensorObject(start, value){
var doc = new Object();
doc.period = new Object();
doc.period["start"] = start;
doc.period["end"] = null;
doc.values = new Array();
var valueObject = new Object();
valueObject["value"] = value;
valueObject["timestamp"] = start;
doc.values.push(valueObject);
return doc;
}
function pushNewValueIntoSensorObject(doc, value, timestamp){
doc["period"]["end"] = timestamp;
var valueObject = new Object();
valueObject["value"] = value;
valueObject["timestamp"] = timestamp;
doc["values"].push(valueObject);
}
function closePeriodInSensorObject(doc) {
doc["period"]["end"] = doc["period"]["start"];
}
// New collection cursor to insert new values.
var sensorNewCursor = db.sensor_new;
// Using the aggregate pipeline to sort and using toArray to iterate through.
var sensorDocuments = db.sensor.aggregate([ { $sort: { "timestamp" : 1}}]).toArray();
// Temp array to store the new sensor objects.
var sensorObjectArray = new Array();
for(var i = 0; i < sensorDocuments.length; i++) {
// Working with the current document.
var currentDocument = sensorDocuments[i];
var value = currentDocument["value"];
var timestamp = currentDocument["timestamp"];
// Initially creating a new document.
if(i === 0) {
var sensorObject = createSensorObject(timestamp, value);
// If there is only one document then we need to close the document.
if(i === (sensorDocuments.Length - 1)) {
closePeriodInSensorObject(sensorObject);
}
// Push into temp array.
sensorObjectArray.push(sensorObject);
}
else{
// Get the previous value.
var previousValue = sensorDocuments[i - 1]["value"];
// Get the latest sensor object from the temp array.
var sensorObject = sensorObjectArray[sensorObjectArray.length - 1];
// When the new value is larger or equal to the previous value.
if(value >= previousValue) {
// Push the new value into the latest sensor object.
pushNewValueIntoSensorObject(sensorObject, value, timestamp);
}
else {
// Create new sensor object.
var sensorObject = createSensorObject(timestamp, value);
sensorObjectArray.push(sensorObject);
}
}
}
print(`Inserting ${sensorObjectArray.length} objects into the db.sensor_new collection.`);
// Insert the whole array into the new collection
sensorNewCursor.insert(sensorObjectArray);
Вы можете использовать функцию load для вызова этого js файла из mongoshell. https://docs.mongodb.com/manual/reference/method/load/
Посмотрите на два снимка экрана.
Наконец-то! Запрос
Вы должны использовать конвейер агрегации, чтобы получить сумму максимального значения для периода.
Сначала нам нужно развернуть значения, затем $ group с $ max, чтобы найти наше максимальное значение, а затем снова сгруппировать, но без поля $ _id для суммирования значений.
db.collection.aggregate([
{
$unwind: "$values"
},
{
$group: {
"_id": "$_id",
"value": {
$max: "$values.value"
}
}
},
{
$group: {
"_id": null,
"total": {
$sum: "$value"
}
}
}
])
Результатом этого запроса будет 28
[
{
"_id": null,
"total": 28
}
]
MongoPlayground в соответствии с новым структура документа: https://mongoplayground.net/p/WblN5QzPoeB
Я действительно надеюсь, что это работает с вашей стороны, если вы не прокомментируете. :)