Mongoose“静态”方法与“实例”方法

Posted

技术标签:

【中文标题】Mongoose“静态”方法与“实例”方法【英文标题】:Mongoose 'static' methods vs. 'instance' methods 【发布时间】:2015-06-22 06:09:13 【问题描述】:

我相信这个问题类似于this one,但术语不同。来自猫鼬4documentation:

我们也可以定义自己的自定义文档实例方法。

// define a schema
var animalSchema = new Schema( name: String, type: String );

// assign a function to the "methods" object of our animalSchema
animalSchema.methods.findSimilarTypes = function (cb) 
  return this.model('Animal').find( type: this.type , cb);

现在我们所有的动物实例都有一个可用的 findSimilarTypes 方法。

然后:

向模型添加静态方法也很简单。继续我们的animalSchema:

// assign a function to the "statics" object of our animalSchema
animalSchema.statics.findByName = function (name, cb) 
  return this.find( name: new RegExp(name, 'i') , cb);


var Animal = mongoose.model('Animal', animalSchema);
Animal.findByName('fido', function (err, animals) 
  console.log(animals);
);

似乎使用静态方法,每个动物实例也可以使用findByName 方法。 Schema 中的 staticsmethods 对象是什么?有什么区别?为什么我要使用其中一个?

【问题讨论】:

【参考方案1】:

statics 是模型上定义的方法。 methods 在文档(实例)上定义。

您可以使用 static 方法,例如 Animal.findByName:

const fido = await Animal.findByName('fido');
// fido =>  name: 'fido', type: 'dog' 

您可能会使用实例方法,例如fido.findSimilarTypes

const dogs = await fido.findSimilarTypes();
// dogs => [ name:'fido',type:'dog , name:'sheeba',type:'dog' ]

但你不会这样做 Animals.findSimilarTypes() 因为 Animals 是一个模型,它没有“类型”。 findSimilarTypes 需要一个 this.type,它在 Animals 模型中不存在,只有一个文档实例会包含该属性,如模型中定义的那样。

同样,您不会¹做fido.findByName,因为findByName 需要搜索所有文档,而fido 只是一个文档。

¹嗯,从技术上讲,您可以,因为实例确实可以访问集合(this.constructorthis.model('Animal')),但拥有一个(至少在这种情况下)没有意义不使用实例中的任何属性的实例方法。 (感谢@AaronDufour 指出这一点)

【讨论】:

@laggingreflex 您的第二条评论不正确。您可以拥有fido.findByName,因为fido 确实可以访问整个集合(通过this.model('Animal'))。但是,拥有一个不使用实例中任何属性的实例方法并没有多大意义。 @lagginreflex 您是否在 mongoosejs.com 上编写了使用实际单词 static 获取免费堆栈点的文档?大声笑它实际上以@Startec 的方式展示了示例,使用Animal.statics.methodName,但随后你出现了,作为我迄今为止在这方面找到的少数资源之一,并且说,基本上不要使用statics 这个词,例如Animals.methodName,但在它显示的文档上。谢谢你,我怀疑这一点。【参考方案2】:

数据库逻辑应该封装在数据模型中。 Mongoose 提供了两种方法,方法和静态。 Methods 向文档添加实例方法,而 Statics 向模型本身添加静态“类”方法。 static 关键字定义模型的静态方法。不会在模型的实例上调用静态方法。相反,它们是在模型本身上调用的。这些通常是实用函数,例如创建或克隆对象的函数。像下面的例子:

const bookSchema = mongoose.Schema(
  title: 
    type : String,
    required : [true, 'Book name required']
  ,
  publisher : 
    type : String,
    required : [true, 'Publisher name required']
  ,
  thumbnail : 
    type : String
  
  type : 
    type : String
  ,
  hasAward : 
    type : Boolean
  
);

//method
bookSchema.methods.findByType = function (callback) 
  return this.model('Book').find( type: this.type , callback);
;

// statics
bookSchema.statics.findBooksWithAward = function (callback) 
  Book.find( hasAward: true , callback);
;

const Book = mongoose.model('Book', bookSchema);
export default Book;

更多信息:https://osmangoni.info/posts/separating-methods-schema-statics-mongoose/

【讨论】:

【参考方案3】:

对我来说,这并不意味着通过在“静态”或什至在“实例”关键字前面添加 Mongoose 来添加任何内容。

我相信静态的含义和目的在任何地方都是相同的,即使对于外星语言或某种代表模型的驱动程序也是如此,用于像另一​​种面向对象编程一样构建块。例如也一样。

来自***: 面向对象编程 (OOP) 中的方法是与消息和对象相关联的过程。对象由数据和行为组成。数据和行为构成一个接口,该接口指定对象的各种消费者[1] 中的任何一个如何使用该对象。

数据表示为对象的属性,行为表示为对象的方法。例如,一个 Window 对象可以具有诸如 open 和 close 之类的方法,而它的状态(在任何给定时间点是打开还是关闭)将是一个属性。

静态方法旨在与类的所有实例相关,而不是与任何特定实例相关。从这个意义上说,它们类似于静态变量。一个例子是一个静态方法,用于对类的每个实例的所有变量的值求和。例如,如果有一个 Product 类,它可能有一个静态方法来计算所有产品的平均价格。

Math.max(双a, 双b)

此静态方法没有拥有对象,并且不在实例上运行。它从其参数中接收所有信息。[7]

即使类的实例尚不存在,也可以调用静态方法。静态方法被称为“静态”,因为它们是在编译时根据调用它们的类来解析的,而不是像实例方法那样动态解析,实例方法是根据对象的运行时类型以多态方式解析的。

https://en.wikipedia.org/wiki/Method_(computer_programming)

【讨论】:

【参考方案4】:

正如大家所说的,当我们想要对单个文档进行操作时使用方法,而当我们想要对整个集合进行操作时使用静态。但是为什么呢?

假设我们有一个架构:

var AnimalSchema = new Schema(
  name: String,
  type: String
);

现在如文档中所述,如果您需要检查数据库中特定文档的相似类型 你可以这样做:

AnimalSchema.methods.findSimilarType = function findSimilarType (cb) 
    return this.model('Animal').find( type: this.type , cb);
;

现在,这里的 this 指的是文档本身。所以,这意味着,这个文件 不知道它属于哪个模型,因为 methods 默认与模型无关,它只针对那个特定的文档 obj。 但是我们可以使用 this.model('anyModelName') 使其与模型一起工作。

现在我们为什么在寻找相似类型动物的情况下使用方法?

为了找到相似类型的动物,我们必须拥有一个动物对象,我们可以找到相似类型的动物。 我们拥有的那个动物对象让我们说: const Lion = await new Animal(name: Lion, type:"dangerous"); 接下来,当我们首先找到需要 Lion obj 的相似类型时,我们必须拥有它。 很简单,每当我们需要特定 obj/document 的帮助来做某事时,我们都会使用方法。

现在这里碰巧我们还需要整个模型来搜索更苗条的类型, 虽然它不能直接在方法中使用(记住 this.modelName 将返回 undefined)。我们可以通过将 this.model() 设置为我们的首选模型来获得它,在本例中为 Animal。 这就是方法的全部内容。

现在,statics 可以使用整个模型。 1)假设您要计算您将使用静态的所有动物的总 价格(假设模型具有价格字段)[因为您不需要任何特定的 Animal obj,所以我们不会使用方法] 2)你想找到有黄色皮肤的动物(假设模型有一个皮肤场),你会使用静力学。 [因为我们不需要任何特定的 Animal obj,所以我们不会使用方法]

例如:

 AnimalSchema.statics.findYellowSkin = function findSimilarType (cb) 
        return this.find( skin: "yellow" , cb);
    ;

请记住,在 this 方法中引用模型,因此,this.modelName 将返回 Animal(在我们的例子中)。

但是就像方法一样,这里我们也可以(但我们不需要)设置模型使用。

AnimalSchema.methods.findSimilarType = function findSimilarType (cb) 
    return this.model('Animal').find( skin: "yellow" , cb);   //just like in methods
;

所以你可以看到静态和方法都非常相似。

每当您有文档并且需要处理该文档时, 使用方法。每当您需要对整体做某事时 模型/集合,使用静态。

【讨论】:

【参考方案5】:.statics 用于static 方法。 将.methods 用于instance 方法。
//instance method
bookSchema.methods.findByType = function (callback) 
  return this.model('Book').find( type: this.type , callback);
;

// static method
bookSchema.statics.findBooksWithAward = function (callback) 
  Book.find( hasAward: true , callback);
;

【讨论】:

【参考方案6】:

staticsmethods 几乎相同,但允许定义直接存在于模型上的函数。

statics 属于 Modelmethods 属于 Instance

【讨论】:

【参考方案7】:

Static methods 适用于定义它们的整个模型,而instance methods 仅适用于集合中的特定文档。

this 在静态方法上下文中返回整个模型,而this 在实例方法上下文中返回文档。

比如说:

const pokemon = new mongoose.Schema()
pokemon.statics.getAllWithType = function(type)
      // Query the entire model and look for pokemon
      // with the same type
      // this.find(type : type)


pokemon.methods.sayName = function()
      // Say the name of a specific pokemon
      // console.log(this.name)



const pokemonModel = mongoose.model('schema', pokemon)
const squirtle = new pokemonModel(name : "squirtle")

// Get all water type pokemon from the model [static method]
pokemonModel.getAllWithType("water")

// Make squirtle say its name [instance method] 
squirtle.sayName()

【讨论】:

以上是关于Mongoose“静态”方法与“实例”方法的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Mongoose 中编写一个获取所有文档的静态方法?

Mongoose:检查对象是不是为猫鼬对象

Egg中使用egg-mongoose和常用的Mongoose 方法

Egg中使用egg-mongoose和常用的Mongoose 方法

使用 Mongoose 的 find() 时遇到问题,正确的使用方法是啥?

Mongoose:用 promise 编写自己的方法