2016-01-26 4 views
0

Итак, я в основном разрабатываю схему временного ряда для своего кода;Обновление вложенных массивов с помощью mongoose

var GameStatisticsSchema = new mongoose.Schema({ 
game: { type: mongoose.Schema.ObjectId, ref: 'Game', required: true }, 
months: [ 
    { // monthly viewers 
     epoch: { type: Number, required: true }, // entry time stamp 
     weeks: [ 
     { // weekly viewers 
      epoch: { type: Number, required: true }, // entry time stamp 
      days: [ 
       { // daily viewers 
        epoch: { type: Number, required: true }, // entry time stamp 
        hours: [ 
        { // hourly viewers 
         epoch: { type: Number, required: true }, // entry time stamp 
         statistics: [ 
         { // per minute statistics. 
          viewers: { type: Number }, 
          channels: { type: Number }, 
         }] 
        }] 
      }] 
     }] 
}] 
}); 

В основном данные хранятся как - поэтому я могу запрашивать данные за день, в минуту, в неделю, как мне нравится;

{ 
"_id" : ObjectId("56a78e337a9a34f8a368f719"), 
"game" : ObjectId("56a6f0b5bbfbbad0550450ee"), 
"months" : { 
    "1" : { 
     "weeks" : { 
      "5" : { 
       "days" : { 
        "26" : { 
         "hours" : { 
          "17" : { 
           "statistics" : { 
            "18" : { 
             "channels" : NumberInt(46), 
             "viewers" : NumberInt(308) 
            } 
           }, 
           "epoch" : NumberInt(1453820400) 
          } 
         }, 
         "epoch" : NumberInt(1453759200) 
        } 
       }, 
       "epoch" : NumberInt(1453672800) 
      } 
     }, 
     "epoch" : NumberInt(1451599200) 
    } 
}, 
"__v" : NumberInt(0) 
} 

В основном я использую findOneAndUpdate(), чтобы вставить мой поминутной данные датчика;

function updateStatistics(game, data) { 

return new Promise(function (resolve, reject) { 

    // get current time 
    var now = moment(); 

    var minute = now.minute(); 
    var hour = now.hour(); 
    var day = now.date(); 
    var week = now.week(); 
    var month = now.month() + 1; // moment months are 0 indexed 

    // we'll store per hour, day, week and month subdocuments. so set the epochs for those. 
    var update = {}; 
    update["months." + month + ".epoch"] = moment().startOf('month').unix(); 
    update["months." + month + ".weeks." + week + ".epoch"] = moment().startOf('isoWeek').unix(); 
    update["months." + month + ".weeks." + week + ".days." + day + ".epoch"] = moment().startOf('day').unix(); 
    update["months." + month + ".weeks." + week + ".days." + day + ".hours." + hour + ".epoch"] = moment().startOf('hour').unix(); 

    // set the viewers & channels. 
    update["months." + month + ".weeks." + week + ".days." + day + ".hours." + hour + ".statistics." + minute + ".viewers"] = data.viewers; 
    update["months." + month + ".weeks." + week + ".days." + day + ".hours." + hour + ".statistics." + minute + ".channels"] = data.channels; 

    GameStatistics.findOneAndUpdate(
     { "game": game._id }, 
     { $set: update }, 
     { 
      new: true, // return the updated document 
      upsert: true, // create the document if does not exist 
      runValidators: true, 
      setDefaultsOnInsert: true 
     }, 
     function(err, document) { 

      if(err) 
      reject(err); 

      resolve(); 
     } 
    ); 
    }); 
    } 

Дело в том, что после включения;

runValidators: true, 
setDefaultsOnInsert: true 

Мой валидатор выпустит исключение;

Cannot update 'months.1.epoch' and 'months' at the same time 

Так, если отключить runValidators, я могу хранить данные как это так, но документ становится схема меньше - и получается identicial к этому;

var GameStatisticsSchema = new mongoose.Schema({ 
game: { type: mongoose.Schema.ObjectId, ref: 'Game', required: true }, 
months: [ { type: mongoose.Schema.Mixed }] 

});

Итак, какие-нибудь обходные пути, которые вы можете предложить?

Причина, по которой я использую upset enabled findOneAndUpdate, заключается в том, что без этого я не знаю, как создавать вложенные значения массива и сохранять() документ.

Имейте в виду, что - за 26.01.2015 15:35:13, код необходимо вставить в это;

months[1].weeks[5].days[26].hours[15].minutes[35].statistics.{ 
viewers = 25; 
channels = 50 
} 

ответ

0

Почему бы не создать временную метку?

var GameStatisticsSchema = new mongoose.Schema({ 
    game: { type: mongoose.Schema.ObjectId, ref: 'Game', required: true }, 
    timestamp: { type: DateTime }, 
    viewers: { type: Number }, 
    channels: { type: Number } 
}); 

Это упрощает обновление, и вы можете использовать запросы dateTime для месяца/дня/и т. Д.

За последний месяц запрос будет:

{ game: gameId, timestamp: { $gt: <date from a month ago>}} 

Но вы должны будете использовать функцию мангуста совокупного который я не слишком хорошо знаком с.

https://docs.mongodb.org/manual/reference/operator/aggregation/avg/

http://mongoosejs.com/docs/api.html#aggregate-js

+0

Потому что я хотел бы получить за неделю, за день, за час, за месяц-данные. С вашим предложением, учитывая, что частота данных метки времени составляет минуту, вы сможете запросить только данные за минуту. С моей текущей схемой я могу запросить, например, данные за неделю, усредняя значения для диапазона дат, который мне нужен. – HuseyinUslu

+0

Вы можете сделать то же самое с запросом даты, усредняя все результаты: find ({date: {$ gt: new Date (2016, 0, 1), $ lt: new Date (2016, 1, 1)}}) for вся статистика в январе –

+0

Хорошо, пожалуйста, покажите мне, как получить данные за последние 4 недели с этим? Посредством усреднения я имею в виду, что я могу подключить обновление схемы и вычислить средние значения за период в документе, а затем это будет простая операция доступа. – HuseyinUslu

Смежные вопросы