上下文:'query'选项在使用mongoose时会做什么?

时间:2016-06-30 07:56:47

标签: javascript node.js mongodb validation mongoose

尝试失败学习练习以使验证者使用'document.update'时,我遇到了一些我不理解的事情。

我现在知道它不起作用,但我尝试过的一件事就是将我的选项设置为{runValidators:true,context:'query'}。在我的验证器函数中,我尝试了console.logging(this),有和没有上下文:“query”选项。

没有区别。我收到一个大对象(这被称为'查询对象'?)这似乎违背了我所读的here

  

在上面的颜色验证功能中,这是指在使用文档验证时验证的文档。但是,在运行更新验证程序时,正在更新的文档可能不在服务器的内存中,因此默认情况下不会定义此值。

即使没有上下文选项,也没有未定义。

我甚至尝试将它作为一个箭头函数,看看这个词汇是否有所不同。在这种情况下, 未定义,但同样,更改上下文选项没有任何区别。 (我还在学习,所以我不知道那部分是否相关)。

在模型中:

let Property = mongoose.model('Property', {
    name: {type:String, required:true},
    occupancy: {type:String},
    maxTenants: Number,
    tenants: [{ type:mongoose.Schema.Types.ObjectId, ref: 'Tenant', validate: [checkMaxTenants, "Maximum tenants exceeded for this property. Tenant not added."]}]
});
function checkMaxTenants(val){
    console.log("this",this);
    // return this.tenants.length <= this.maxTenants;
    return true;
}

并在路线中:

        property.update({$set: {tenants:property.tenants}},{new:true,runValidators:true,context:'query'}, function(err,savedProperty){

任何可以帮助我更好地理解我认为我正在阅读的内容与我看到的内容之间的差异会很棒!

1 个答案:

答案 0 :(得分:5)

首先,我们要清楚验证器有两种类型:文档验证器和更新验证器(也许您已经知道了,但您发布的片段更新了文档,您提到的问题是文档验证)。

  

没有区别。我收到一个大对象(这被称为'查询对象'?)这似乎违背了我在这里读到的内容。

当您在文档中提到的文档上运行save时,将运行文档验证程序。

  

验证是中间件。默认情况下,Mongoose将验证注册为每个模式的pre('save')挂钩。

或者您可以使用.validate()

手动调用它
  

您可以使用doc.validate(回调)或doc.validateSync()

手动运行验证

运行更新验证程序以进行更新操作

  

在上面的示例中,您了解了文档验证。 Mongoose还支持update()和findOneAndUpdate()操作的验证。

这可以通过以下代码段来说明。为方便起见,我已将tenants的类型更改为一个简单的整数数组,但这对我们讨论的目的而言非常重要。

// "use strict";

const mongoose = require('mongoose');
const assert = require('assert');
const Schema = mongoose.Schema;

let Property = mongoose.model('Property', {
  name: { type: String, required: true },
  occupancy: { type:String },
  maxTenants: Number,
  tenants: [
    {
      type: Number,
      ref: 'Tenant',
      validate: {
        validator: checkMaxTenants,
        message: "Maximum tenants exceeded for this property. Tenant not added."
      }
    }
  ]
});

function checkMaxTenants (val) {
  console.log("this", this);
  // return this.tenants.length <= this.maxTenants;
  return true;
}

mongoose.Promise = global.Promise;
mongoose.createConnection('mongodb://localhost/myapp', {
  useMongoClient: true,
}).then(function(db) {

  const property = new Property({ name: 'foo', occupancy: 'bar', tenants: [1] });

  property.update(
    { $set: { tenants: [2, 3] } },
    {
      new: true,
      runValidators: true,
      // context: 'query'
    },
    function(err, savedProperty) {

    }
  )

  // property.save();
});

以上代码触发更新验证不是文档验证

要查看操作中的文档验证,请取消注释property.save()并注释更新操作。

您会注意到这个值将是property文档。

this { name: 'foo',
occupancy: 'bar',
_id: 598e9d72992907120a99a367,
tenants: [ 1 ] }

注释保存,取消注释更新操作,您将看到您提到的大对象。

现在你可能没有意识到的大对象是你设置上下文时没有设置context: 'query'和查询对象的全局对象。

这可以在mongoose的来源this line解释。如果未设置上下文,则mongoose会将范围设置为null。然后here使用.call调用scope

现在,在非严格模式下,使用null this is replaced with the global object调用.call时。所以检查你得到的大对象的内容。如果未设置context,则它将是全局对象而不是查询对象。您可以添加"use strict";并查看将记录的null。 (发布的片段可以为您验证)。您可以通过针对mongoose.Query运行instanceof this来验证您是否拥有查询对象。

希望这有助于您更好地理解事物。