2016-01-22 25 views
5

Tôi sử dụng mongodb 2.6. Tôi đã lưu trữ dữ liệu của tôi dưới hình thức này:Nhóm Theo tập hợp trên MongoDb

{ 
    "_id" : "my-sensor-1", 
    "points": [ 
     { "timeStamp" : NumberLong("1453468362174"), "value" : 41 }, 
     { "timeStamp" : NumberLong("1453468483297"), "value" : 66 }, 
     { "timeStamp" : NumberLong("1453468485568"), "value" : 49 }, 
     ...  
    ] 
} 

Để tổng hợp các tài liệu tôi làm cho các truy vấn như thế này:

db.pointsTest.aggregate([ 
    { $match: { $and: [ {"points.timeStamp" : { $gt : 1453433925163}}, 
         {"_id":"my-sensor-10"} ] } }, 
    {"$unwind":"$points"}, 
    {$group: {_id: "my-sensor-1","average":{$avg : "$points.value"}}} 
]) 

{ "_id": "my-cảm biến-1 ", "trung bình": 52}

quả

Tôi đã lưu dấu thời gian bằng mili giây nên mỗi lần tôi muốn tổng hợp một khoảng thời gian cụ thể, tôi phải thay đổi giới hạn của giá trị timeStamp.

Làm cách nào để tổng hợp trong một khoảng thời gian và nhóm kết quả theo khoảng cách khoảng thời gian (tức là tổng hợp giá trị trung bình từ bây giờ() -1day GROUP by 1h)?

EDIT

Tôi muốn làm một cái gì đó như thế này:

db.pointsTest.aggregate([ 
    { $match: { $and: [ {"points.timeStamp" : { $gt : 1453433925163, $lt : 1453555555555}}, {"_id":"my-sensor-10"} ] } }, {"$unwind":"$points"}, {$group: {_id: "my-sensor-1","average":{$avg : "$points.value"}, ???}} 
]) 

và kết quả sẽ là mức trung bình của khoảng thời gian này được phân nhóm theo 1h. Giả sử rằng tôi muốn tổng hợp các giá trị trung bình cho mỗi giờ trong 31 Tháng Mười Hai:

dấu thời gian của khoảng thời gian 31/12/2015 20:00:00, trung bình: xyz

dấu thời gian của khoảng 31/12/2015 21:00:00, trung bình: xyz

Tại thời điểm này để đạt được điều đó tôi phải chia khoảng thời gian trong khoảng thời gian 1 giờ và thực hiện một số yêu cầu đến cơ sở dữ liệu.

IE sử dụng InfluxDB làm như vậy tôi làm điều này:

"SELECT MEAN(value) From myMeasures where key='my-sensor-1' and time > now() - 1d GROUP BY time(1h)" 

Trả lời

1

Bạn cần thực hiện một số phép tính toán trong truy vấn Mongo để nhóm dữ liệu dựa trên khoảng thời gian khác nhau.

Kết hợp $ trừ và $ mod sẽ giúp bạn nhóm dữ liệu trong khoảng thời gian cụ thể.

Truy vấn sẽ như thế nào sau đây:

db.sensor.aggregate({ 
    $match: { 
    $and: [{ 
     "points.timeStamp": { 
      $gt: 1453433925163, 
      $lt: 1453555555555 
     } 
    }, { 
     "_id": "my-sensor-1" 
    }] 
    } 
}, { 
    $unwind: "$points" 
}, { 
    "$group": { 
    "_id": { 
     "$subtract": ["$points.timeStamp", { 
      "$mod": ["$points.timeStamp", 1000 * 60] 
     }] 
    }, 
    "average": { 
     "$avg": "$points.value" 
    } 
    } 
}) 

Hope, điều này sẽ rất hữu ích cho bạn.

+0

thực sự hữu ích nhưng tôi nghĩ rằng nó thiếu một cái gì đó (có lẽ tôi đã không xác định nó trên câu hỏi của tôi). Để lặp lại các mục trong danh sách, tôi phải thêm một $ match khác vì khi điều kiện là true thì nó trả về toàn bộ các mục. Vì vậy, truy vấn giống như sau: db.pointsTest.aggregate ({$ match: {$ và: [{"points.timeStamp": {$ gte: 1453797806927}}, {"_id": "my-sensor-1"} ]}}, {$ giãn ra: "$ điểm"}, {$ match: {"points.timeStamp": {$ gte: 1453797806927}}}, {"$ group": {"_id": {"$ trừ" : ["$ points.timeStamp", {"$ mod": ["$ points.timeStamp", 1000 * 60]}]}, "trung bình": {"$ avg": "$ points.value"}}}) – bill

1

Để có được kết quả trong khoảng thời gian khoảng cách, bạn có thể tận dụng chức năng javascript để hỗ trợ truy vấn của bạn, vì vỏ MongoDB hỗ trợ họ:

thực hiện ví dụ với ví dụ mà bạn cung cấp, nơi bạn muốn $match giá trị từ now()-1day, bạn có thể làm điều này trước khi tập hợp của bạn:

var now = new Date(); 
var yesterday = new Date(); 
// using getHours and setHours, since the Date object doesnt have method for getDays and setDays 
yesterday.setHours(now.getHours() - 24); 

yesterday.getTime() sẽ mang lại ngày trong milis, mà bạn có thể sử dụng nó trong tập hợp của bạn trong giai đoạn $match

db.pointsTest.aggregate([ 
    { $match: { $and: [ {"points.timeStamp" : { $gt : yesterday.getTime()}}, 
         {"_id":"my-sensor-10"} ] } }, 

Bây giờ để kết quả nhóm trong khoảng thời gian hàng giờ, tôi muốn thêm một giai đoạn $project trước $group, để thêm một trường mới, trong đó khoảng thời gian hàng giờ được tính toán, với points.timeStamp - yesterday.getTime() bạn sẽ nhận được sự khác biệt tổng số mili giây giữa thời gian ban đầu và thời gian nhập, bạn chuyển đổi thành giờ và làm tròn đến giá trị số nguyên tiếp theo.

Và cuối cùng, sử dụng trường mới đó từ giai đoạn $project, sẽ được sử dụng trong giai đoạn $group.

1

Bạn có thể dễ dàng thực hiện việc này với mongodb mapReduce.

Hãy thử đoạn mã sau:

// generate a query to filter result by date and _id. 
// be aware that our query matches documents that contain an array field with 
// at least one element that matches all the specified criteria. 
var yesterday = new Date(); 
yesterday.setDate(yesterday.getDate()-1); 
var query = {"points.timeStamp" : { $gt : yesterday.getTime()}, "_id":"my-sensor-1"}; 

var map = function(){ 
    var points = this.points; 
    for(var i=0;i<points.length;i++){ 
     var date = new Date(points[i].timeStamp); 

     //remove minutes, seconds and milliseconds from the date and emit it 
     date.setHours(date.getHours(), 0, 0, 0); 
     emit(date, points[i].value); 
    } 
}; 

var reduce = function(key, values){ 
    //calculate average 
    var total = 0; 
    for(var i = 0; i < values.length; i++) { 
     total += values[i]; 
    } 
    var avg = total/values.length; 
    return avg; 
}; 

db.pointsTest.mapReduce(map, reduce, {out:{inline: 1}, query: query}) 
Các vấn đề liên quan