【问题标题】:How do i update a field in mongodb?如何更新 mongodb 中的字段?
【发布时间】:2017-01-15 18:13:02
【问题描述】:

我的目标是更新 itemSchema 中每个对象的 timeleft 字段。

const ItemSchema = mongoose.Schema({
    name: String,
    time: { type: Date, default: Date.now },
    timeleft: { type: Number, default: 24 }
});

例如为了让我更新ItemSchema中的每个对象

ItemSchema.methods.calculateTime = function() { // Done check it one hour

  var currentTime = moment() // Get current Time
  var timeStored = moment.utc(this.time).local().format(); // Convert this.time UTC to local time
  var timeDiff = currentTime.diff(timeStored, 'h'); // See the difference in time example - 7
  this.timeleft -= timeDiff; // Deduct timeleft witht he timeDiff , result would be 17
  this.save(); // Simple save it to the database
}

API 示例

app.get('/allItems', function(req, res) {
    Item.find({}, function(err, items) {
      // I want to run items.calculateTime(); but it is not possible.
      // How would I run calculateTime function on the array of objects?
    });
});

我的目标是不断检查时差并将其保存到剩余时间

数据示例

timeleft: 24

// after calculateTime
time: 17 

Because I want to show this to the User

// 17 hours left

如何对对象数组而不是单个对象执行此操作?

【问题讨论】:

  • 查看您的用例,我不会将此值保存到数据库中,而是在查询时动态计算。看看 Mongoose 的虚拟吸气剂。
  • 所以数据不会保存到timeleft字段?
  • 是的。据我了解,是可以从time属性算出来的吧?
  • 时间是日期类型,我之所以添加timeleft,是为了以后可以根据timeleft字段查询
  • 例如,如果timeleft0,则不要向用户显示此内容。

标签: mongodb mongoose


【解决方案1】:

查看您的用例,我建议您修改解决问题的方法。显然,您正在创建具有“到期日期”的项目(或类似的东西,我将在下面使用术语“到期”)。有效期为自项目创建之日起 24 小时。

我不会将timeLeft 的值保存到数据库,而是在查询时动态重新计算它。 (1)这是多余的,因为它可以从当前时间和time值计算出来,据我了解你的问题,(2)你必须不断更新timeleft属性,这看起来很尴尬。

您可以使用猫鼬的virtuals

更改架构以确保在创建对象时返回虚拟对象:

const ItemSchema = mongoose.Schema({
  name: String,
  time: { type: Date, default: Date.now }
}, {
  // enable, to have the property available, 
  // when invoking toObject or toJSON
  toJSON: {
    virtuals: true
  },
  toObject: {
    virtuals: true
  }
});

定义虚拟属性timeLeft(我将代码更改为在没有moment的情况下工作):

// the virtual property, which is not stored in the DB,
// but calculated after querying the database
ItemSchema.virtual('timeLeft').get(function() {
  var millisecondsDifference = Date.now() - this.time.getTime();
  var hoursDifference = millisecondsDifference / (1000 * 60 * 60);
  return Math.max(0, 24 - hoursDifference); // cap to 24 hours
});

您不能查询虚拟属性,因为它们显然不存在于数据库中。相反,当您要查询已达到到期日期的项目时,您可以搜索在过去 24 小时内创建的项目。为了方便地执行此操作并将代码放在中心位置,您可以将静态方法附加到您的架构,您可以使用ItemModel.findNonExpired 调用它:

// put the logic for querying non-expired items into
// its own static function, which makes it easier to
// reuse this functionality and understand what's going on
ItemSchema.statics.findNonExpired = function(callback) {
  return this.find({
    time: {
      // find items which have a time within 
      // the last 24 hours
      $gt: new Date(Date.now() - 1000 * 60 * 60 * 24)
    }
  }, callback);
};
const ItemModel = mongoose.model('Item', ItemSchema);

演示:

// create and save some some test items
const items = [
  { name: 'created now' },
  { name: 'created an hour ago', time: new Date(Date.now() - 1000 * 60 * 60) },
  { name: 'created yesterday', time: new Date(Date.now() - 1000 * 60 * 60 * 24) },
  { name: 'created two days ago', time: new Date(Date.now() - 1000 * 60 * 60 * 24 * 2) },
];
ItemModel.create(items, function(err) {
  if (err) throw err;

  ItemModel.findNonExpired(function(err, items) {
    if (err) throw err;
    console.log(items);
  });
});

[编辑] 这是一个完整的演练,您应该能够复制和粘贴,而无需进行任何大的更改。

【讨论】:

  • 我编辑了要包含的问题,将找到所有项目的 api。问题是我应该把$gt: new Date()放在哪里?
  • 而在虚拟中,我如何将timeleft设置为24?,是不是简单的this.timeleft = 24
  • 我尝试查询,但似乎没有返回timeleft 属性。
  • @sinusGob 已编辑答案。
  • 所以从技术上讲,我什至不需要使用虚拟?因为const query和virtual完全没有关系,但是如果我想用virtual呢?
猜你喜欢
  • 2017-02-09
  • 1970-01-01
  • 2015-12-24
  • 2017-06-14
  • 1970-01-01
  • 2014-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多