使用mongoose更新嵌套数组

时间:2016-01-26 15:28:53

标签: arrays mongodb mongoose nested

所以我基本上为我的代码开发了一个时间序列模式;

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,我可以这样存储数据,但是文档变得没有模式 - 并且变成了对此的识别;

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

});

您可以建议任何变通方法吗?

我使用upset启用findOneAndUpdate的原因是,如果没有我不知道如何创建嵌套数组值并保存()文档。

请记住 - 对于2015年1月26日15:35:13,代码需要插入到此中;

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

1 个答案:

答案 0 :(得分: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