【问题标题】:When exactly does Mongoose's .pre('init') get called?Mongoose 的 .pre('init') 究竟什么时候被调用?
【发布时间】:2018-09-20 23:08:15
【问题描述】:

我想创建“游戏”,每个游戏都有自己独特的访问“代码”。架构中的代码是required,每次创建新游戏时我都需要生成一个代码。

我认为schema.pre('init') 将是生成此访问代码的好地方:

GameSchema.pre('init', function(next) {
    // Code generation logic happens here
    this.code = myNewlyGeneratedCode
    next()
}

不幸的是,这会返回一条错误消息:ValidationError: Game validation failed: code: Path 'code' is required.

为什么这不起作用?在我实例化一个新游戏之前,我是否必须创建一个code

【问题讨论】:

  • "init" 事件在您检索文档时被调用。你需要.pre('save')
  • 我避免使用.pre('save'),因为我不想每次保存对游戏文档的更改时都重新生成游戏代码。正如我在下面的评论中提到的,我认为 .pre('validate') 是我正在寻找的。​​span>
  • "validate" 也会在每次对文档进行更改时调用,因此您无法避免该问题。
  • 啊,是的,好点。我想我需要在pre-save 中使用this.isNew,如下面的lineus 所建议。只是感觉猫鼬应该对这种东西有更好的支持;看起来会很常见。
  • 经过进一步测试,我发现我无法使用pre-save,因为MongoDB仍然抱怨code路径是必需的。我最终在pre-validate 中使用this.isNew 来完成工作。

标签: node.js mongoose mongoose-schema


【解决方案1】:

如 cmets 中所述,pre('save') 是在您的文档存储到数据库之前运行的中间件。 pre('init') 在您的文档从 mongodb 查询返回时被调用。

演示文档中间件顺序的最简单方法是通过一个简单的示例:

49768723.js

#!/usr/bin/env node
'use strict';

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
const Schema = mongoose.Schema;

var count = 0;

const schema = new Schema({
  name: String
});

function log(str) {
  console.log(`${++count}: ${str}`);
}

schema.pre('save', function () {
  log('pre-save');
});

schema.pre('init', function () {
  log('pre-init');
});

schema.post('save', function () {
  log('post-save');
});

schema.post('init', function () {
  log('post-init');
});

schema.pre('validate', function () {
  log('pre-validate');
});

schema.post('validate', function () {
  log('post-validate');
});

schema.pre('remove', function () {
  log('pre-remove');
});

schema.post('remove', function () {
  log('post-remove');
});


const Test = mongoose.model('test', schema);

const test = new Test({ name: 'Billy' });

async function main() {
  await test.save();
  log('saved');
  await Test.findOne({ _id: test.id });
  log('found');
  await test.remove();
  log('removed');
  return mongoose.connection.close();
}

main();

输出

stack: ./49768723.js
1: pre-validate
2: post-validate
3: pre-save
4: post-save
5: saved
6: pre-init
7: post-init
8: found
9: pre-remove
10: post-remove
11: removed
stack:

【讨论】:

  • 很好的例子,谢谢!看起来pre-validate 是我应该使用的,因为我不想每次save 更改游戏文档时都重新生成代码。
  • 您也可以在预保存挂钩中使用类似“if (this.isNew) { this.code = gencode() }”的测试来生成代码。 This.isNew 只会在第一次保存时为真(除非您稍后再次明确设置它)。我认为这个策略稍微干净一些,因为你的钩子的目的是“保存”一个特殊的属性,而不是验证一些东西。
  • 我想问一下,这个执行顺序背后的逻辑是什么,我对术语感到困惑,通常曾经认为“init”是大多数流程中发生的第一件事,在这里首先执行前和后保存完成,然后执行前和后初始化。
猜你喜欢
  • 2015-10-12
  • 2014-09-09
  • 2023-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-31
  • 2021-04-15
相关资源
最近更新 更多