【问题标题】:How can I retrieve documents' properties from a pre hook?如何从预挂钩中检索文档的属性?
【发布时间】:2018-12-22 22:36:45
【问题描述】:

我昨天发布了这个问题,因为我不知道如何解决我的问题。

Change variable value in document after some time passes?

有人告诉我我需要使用预钩。我试图这样做,但“this”指的是查询,而不是文档。所以我无法检索文件来检查 4 周是否过去了。 (检查问题,你会得到它)

因为我不知道如何让这个 .pre('find') 使用我每个文档中的变量(所以它会检查 4 周是否过去了)我正在考虑遍历所有这些变量并检查是否4 周过去了。

router.get('/judet/:id([0-9]{2})', middleware.access2, function(req, res)
{
      var title = "Dashboard";
      Somer.find({}, function(err, someri)
      {
        if(err)
        {
            console.log(err);
        }
        else
        {
            res.render("dashboard", {title: title, id:req.params.id, someri:someri});
        }
      });
}); ///get route
var someriSchema = new mongoose.Schema({
    nume: {type: String, required: true},
    dateOfIntroduction: {type:Date, default: Date.now, get: formatareData},
});

someriSchema.pre('find', function(next) {
    console.log(this.dateOfIntroduction); <- this will return undefined, because this refers to the query, actually
    next();
});///schema and the pre hook. I thought I could use it like this, and inside the body of the pre hook I can check for the date

这就是我要说的:

router.get('/judet/:id([0-9]{2})', middleware.access2, function(req, res)
{
      var title = "Dashboard | Best DAVNIC73";
      Somer.find({}, function(err, someri)
      {
        if(err)
        {
            console.log(err);
        }
        else
        {
            someri.forEach(function(somer)
            {
            ///check if 4 weeks passed and then update the deactivate variable
            })
            res.render("dashboard", {title: title, id:req.params.id, someri:someri});
        }
      });
});

但我认为如果我的数据库中有很多条目,这将是非常糟糕的性能,我认为这不是最好的方法。

那么,如果我被正确告知并且我应该使用 pre hook 来获取我所说的内容,我怎样才能让它引用文档?

【问题讨论】:

    标签: node.js mongodb mongoose


    【解决方案1】:

    好的,我想我了解您的要求。这是你可以做的:

    /*
      this will always set a documents `statusFlag` to false, if the 
      `dateOfIntroduction` was before Date.now()
    */
    const mongoose = require('mongoose')
    someriSchema.pre('find', function(next) {
      mongoose.models.Somer.update(
       { datofIntroduction: { $lte: new Date() }}, 
       { statusFlag : false})
       .exec()
       .then((err, result) => {
         // handle err and result
         next();
       }); 
    });
    

    我看到的唯一问题是,您在每次查找时都会触发此请求。

    【讨论】:

    • 乍一看,它似乎可以解决问题。它怎么知道“用户”是什么?据我所知, .pre 应该在模型声明之前插入。所以在那之前,用户将是未定义的。 (我说的对吗?)
    • 你完全正确,我更新了我的答案以既适合你的模式,也包括一些惰性初始化直接通过 mongoose.models 访问模型。这样,我们将只访问 Somer 的初始化版本,因为这个钩子只会在服务器启动和模型初始化之后被调用。
    • 它似乎会起作用。我不能检查它,我明天会做。如果它有效,我会接受它是正确的。非常感谢您的宝贵时间。
    • 没问题,我们不久前遇到了类似的问题,试图在创建时将手动生成的 ID 分配给一些文档,这就是为什么我仍然有那个 hacky sn-p 飞来飞去的原因。
    • “我看到的唯一问题是,您在每次查找时都会触发此请求。”我怎样才能解决这个问题?你有更好的选择吗?
    【解决方案2】:

    在查询中间件中,mongoose 不一定引用 正在更新的文档,所以 this 指的是查询对象而不是 比正在更新的文档。

    直接取自mongoose的文档

    我昨天向您指出了他们的文档;但这里有一个更具体的答案。

    someriSchema.post('find', function(res) {
      // res will have all documents that were found
      if (res.length > 0) {
        res.forEach(function(someri){
            // Do your logic of checking if 4 weeks have passed then do the following
            someri.deactivated = true
            someri.save()
        })
      }
    })
    

    这基本上做的是对于每个找到的模式,您将相应地更新它们的属性,如果您只查询 1 个对象,您的 res 只能有 1 个对象。您的第二个解决方案是执行cron

    编辑:这是解决异步问题的方法

    const async = require('async')
    
    someriSchema.post('find', function(res) {
      async.forEach(res, function(someri, callback) {
           // Do your logic of checking if 4 weeks have passed 
           // then do the following - or even better check if Date.now() 
           // is equal to expiryDate if created in the model as suggested
           // by `BenSow`
    
           // Then ONLY if the expiry is true do the following
           someri.deactivated = true
           someri.save(function (err) {
                err ? callback(err) : callback(null)
           })
      }, function(err){
         err ? console.log(err) : console.log('Loop Completed')
      })
    })
    

    【讨论】:

    • 不是这个解决方案的忠实拥护者,因为你会遇到这个解决方案的竞争条件,因为 forEach + save() 可能是异步的,不能真正等待,对吧?
    • 我可以在 get 路线中做到这一点,但正如我所说,如果我有一个包含大量条目的数据库,我认为这在性能方面非常费力。
    • 不可以等待,尤其是 save 有回调。唯一的其他选择是cron。使用回调它可以是这样的。 someri.save(err=>{}) 如果您想在移动到下一个文档之前等待上一个文档,则必须将其插入异步循环。没有办法更改文档,但根据要求,使用 mongoose。这种支持是不存在的。您可以随时返回并使用 .save 以外的其他内容,但归结为相同的内容
    • 就复杂性而言。是的,这非常复杂,而且不是最佳解决方案,但有一些方法可以通过编写您自己的钩子和您自己的模型来使其更加优化。但是,您的问题与复杂性无关。请记住,无论您是否实施此解决方案,post('find') 都会始终运行,所以在这里我们只是检查,然后仅在需要时保存
    • @MuhandJumah 没错,可以创建一系列回调,并一个接一个地等待它们,但无论是代码还是性能,这都有一些代码味道。我不同意除了 cron 之外别无选择,正如我在回答中所展示的那样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-25
    • 1970-01-01
    • 2021-10-05
    相关资源
    最近更新 更多