Looking for a way to manipulate some fields in mongoose(likely how middleware works) but without having to resort to any backend code

huangapple go评论112阅读模式
英文:

Looking for a way to manipulate some fields in mongoose(likely how middleware works) but without having to resort to any backend code

问题

感谢您的关注,我正在使用MERN堆栈进行工作,尝试做一些不如我所期望的事情(如果这变成了一个重复的问题,我对Web开发是新手,我很抱歉)。

以下是您提到的三个部分的翻译:

1.) 有一个名为'Lead'的模式,其中包含许多字段,其中一个是'status',当Lead的状态从'stageX'更改为'stageY'时,我希望特定文档更新一个字段'stageYdate'(最初为null)并使用当前日期。

2.) 无论以前存在的路由和请求如何,我都希望发生这种情况,该字段应根据'status'字段进行更新,因此需要在模型级别创建一个中间件(不确定是否应该是文档级别的中间件)。

3.) 尝试在模拟模式/模型上执行操作,但它也不起作用。

制作模式并导出模型:

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

const ModelMiddlewareSchema = new mongoose.Schema({
  stage: {
    type: String
  },
  stageChangeDate:{
    type: Date,
  }
});
const ModelMiddleware = mongoose.model('ModelMiddleware', ModelMiddlewareSchema);
// 在这里尝试使用中间件在"ModelMiddleware"上,但不起作用 :(
module.exports = ModelMiddleware; 

它会报错,说ModelMiddleware.pre()函数未定义,所以我必须在路由中使用它:

const ModelMiddleware = require('../models/modelMiddlewareCheck');
const express = require('express');
const router = express.Router();

const logMiddleware = async function(next) {
  console.log(`保存文档 ${this._id}`);
  this.stage = 'stage2';
  next();
};

ModelMiddleware.schema.pre('save', logMiddleware);

router.put('/', async (req, res) => {
  try {
    console.log('接收到的请求为', req.body);
    const newDoc = new ModelMiddleware();
    newDoc.stage = 'stage1';
    await newDoc.save();
    return res.status(200).send('成功创建stage1');
  } catch (err) {
    console.log(err);
    res.status(400).send('操作失败');
  }
});

module.exports = router;

以上是模拟,但我想要做类似于以下的操作:

const stage_initial = this.stage;

const postStageCheck = function(next){
const stage_final = this.stage;
if(stage_initial==='stage1' && stage_final==='stage2'){
    this.stageChangeDate = new Date();
    this.save()
 }
next();
}
ModelMiddleware.post('save', postStageCheck)
英文:

Thanks for your valuable attention, I'm working on MERN stack & trying to do something that's not working like I am expecting it to be.(Sorry if this turns out to be a repeated question, I'm new to web dev).

Here Goes

1.) There is this 'Lead' schema that contains many fields, one particular being 'status', when status is changed from 'stageX' to 'stageY' for a Lead, I want that particular document to update a field 'stageYdate'(initially null) with the current Date.

2.) I want this to happen regardless of previous existing routes and requests, the field should update depending upon the 'status' field, so a model level middleware(not sure if it should be document level instead)

3.) Tried performing operation on a mock schema/model and it isn't working either.

Making schema and exporting model

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

const ModelMiddlewareSchema = new mongoose.Schema({
  stage: {
    type: String
  },
  stageChangeDate:{
    type: Date,
  }
});
const ModelMiddleware = mongoose.model('ModelMiddleware', ModelMiddlewareSchema);
//Tried using middleware here on "ModelMiddleware", didn't work :(
module.exports = ModelMiddleware; 

It was giving error that ModelMiddleware.pre() function is not defined so i had to use it in routes

const ModelMiddleware = require('../models/modelMiddlewareCheck');
const express = require('express');
const router = express.Router();

const logMiddleware = async function(next) {
  console.log(`Saving document ${this._id}`);
  this.stage = 'stage2'
  next();
};

ModelMiddleware.schema.pre('save', logMiddleware);

router.put('/', async (req, res) => {
  try {
    console.log('req received as', req.body);
    const newDoc = new ModelMiddleware();
    newDoc.stage = 'stage1';
    await newDoc.save();
    return res.status(200).send('stage1 created successfully');
  } catch (err) {
    console.log(err);
    res.status(400).send('unsuccessful operation');
  }
});

module.exports = router;

Above was mock but i want to do something like this

const stage_initial = this.stage;

const postStageCheck = function(next){
const stage_final = this.stage;
if(stage_initial==='stage1' && stage_final==='stage2'){
    this.stageChangeDate = new Date();
    this.save()
 }
next();
}
ModelMiddleware.post('save', postStageCheck)

答案1

得分: 1

这段代码是用来在MongoDB中监测阶段变化并添加日期字段的。以下是翻译后的代码部分:

const mongoose = require("mongoose");

const ModelMiddlewareSchema = new mongoose.Schema({
  stage: {
    type: String
  },
  stageChangeDate: {
    type: Date
  }
});

ModelMiddlewareSchema.pre('update', function(next) {
    console.log('pre middleware is fired update')
    const currentStatus = this.stage
  
    if(this.isModified('stage')) {
      const newStatus = this.status

      if (currentStatus === 'stage1' && newStatus === 'stage2') {
        this.stageChangeDate = new Date()
        console.log('new date is added')
      }
    }
    next();
  });

ModelMiddlewareSchema.pre('save', function(next) {
    console.log('pre middleware is fired save')
    const currentStatus = this.stage
  
    if(this.isModified('stage')) {
      const newStatus = this.status

      if (currentStatus === 'stage1' && newStatus === 'stage2') {
        this.stageChangeDate = new Date()
        console.log('new date is added')
      }
    }
    next();
  });

ModelMiddlewareSchema.pre('findOneAndUpdate', async function(next) {
    console.log('pre middleware is fired findOneAndUpdate')

    const update = this.getUpdate(); // 访问更新对象

    console.log('update is ', update)

  if (update && update['$set'].stage) {
    const document = await this.findOne();
    const project = await projects.findOne();

    console.log('document is ', document)
    const currentStatus = document.stage;
    const updatedStatus = update['$set'].stage;
    console.log('currentStatus is ', currentStatus)
    console.log('updatedStatus is ', updatedStatus)

    if (currentStatus === 'stage1' && updatedStatus === 'stage2') {
    update.$set.stageChangeDate = new Date();
    console.log('update after adding date is ', update)
    }
  }
    next();
  });

const ModelMiddleware = mongoose.model('ModelMiddleware', ModelMiddlewareSchema);

module.exports = ModelMiddleware;
英文:

This worked in adding date field by monitoring stage change in mongo

const mongoose = require("mongoose");
const ModelMiddlewareSchema = new mongoose.Schema({
stage: {
type: String
},
stageChangeDate: {
type: Date
}
});
ModelMiddlewareSchema.pre('update', function(next) {
console.log('pre middleware is fired update')
const currentStatus = this.stage
if(this.isModified('stage')) {
const newStatus = this.status
if (currentStatus === 'stage1' && newStatus === 'stage2') {
this.stageChangeDate = new Date()
console.log('new date is added')
}
}
next();
});
ModelMiddlewareSchema.pre('save', function(next) {
console.log('pre middleware is fired save')
const currentStatus = this.stage
if(this.isModified('stage')) {
const newStatus = this.status
if (currentStatus === 'stage1' && newStatus === 'stage2') {
this.stageChangeDate = new Date()
console.log('new date is added')
}
}
next();
});
ModelMiddlewareSchema.pre('findOneAndUpdate', async function(next) {
console.log('pre middleware is fired findOneAndUpdate')
const update = this.getUpdate(); // Access the update object
console.log('update is ', update)
if (update && update['$set'].stage) {
const document = await this.findOne();
const project =await projects.findOne();
console.log('document is ', document)
const currentStatus = document.stage;
const updatedStatus = update['$set'].stage;
console.log('currentStatus is ', currentStatus)
console.log('updatedStatus is ', updatedStatus)
if (currentStatus === 'stage1' && updatedStatus === 'stage2') {
update.$set.stageChangeDate = new Date();
console.log('update after adding date is ', update)
}
}
next();
});
const ModelMiddleware = mongoose.model('ModelMiddleware', ModelMiddlewareSchema);
module.exports = ModelMiddleware;

答案2

得分: 0

使用模型中间件是执行检查的方式,不管更新来自何处都适用。

但是,我会使用"pre"而不是"post",然后您可以将"stageChangeDate"更新与新状态更新捆绑在一起,这将减少对数据库的请求数量。

英文:

The usage of a model middleware is the way to go to permform the check regardless of where the update is coming from.

However, I would use pre instead of post, then you can bundle the stageChangeDate update together with the new status update which would reduce the number of requests to the database.

const schema = new Schema({ /* ... */ });
schema.pre('save', function(next) {
const currentStatus = this.status
if (this.isModified('status') {
const newStatus = this.status
if (currentStatus === 'x' && newStatus === 'y') {
this.stageChangeDate = new Date()
}
}
next();
});

答案3

得分: 0

整体上走对了方向,但需要做一些修改。

您希望在保存文档之前修改它,因此请使用 pre 中间件而不是 postpost 在文档保存后执行,所以太晚了,无法进行修改。

如果要将先前的状态与新状态进行比较,您需要手动存储先前的状态。您可以通过结合使用 prepost 来实现此目标。

// 用于存储初始状态的预保存中间件
ModelMiddlewareSchema.pre('save', function(next) {
  // 在文档上存储初始状态
  this._initialStage = this.stage;
  next();
});

// 用于检查更改并更新的后保存中间件
ModelMiddlewareSchema.post('save', async function(doc) {
  if (this._initialStage === 'stage1' && this.stage === 'stage2') {
    // 更新 stageChangeDate 字段
    this.stageChangeDate = new Date();
    // 保存更新后的文档
    await this.save();
  }
});

以上是您要的翻译部分,不包含代码。

英文:

Overall on the right track but needs a few changes.

You want to modify the document before it's saved so use pre middleware instead of post. post is executed after the document has been saved so it's too late to make changes.

You need to manually store the previous state if you want to compare it to the new state. You can do this by using a combination of pre and post.

// Pre-save middleware to store the stage
ModelMiddlewareSchema.pre('save', function(next) {
// Store the initial stage on the document
this._initialStage = this.stage;
next();
});
// Post-save middleware to check for change and update
ModelMiddlewareSchema.post('save', async function(doc) {
if (this._initialStage === 'stage1' && this.stage === 'stage2') {
// Update the stageChangeDate field
this.stageChangeDate = new Date();
// Save the updated document
await this.save();
}
});

答案4

得分: -1

您可以在模式定义中使用虚拟属性(virtual properties)、getter 和 setter 来修改 Mongoose 模式中的字段,而无需使用后端代码。这些功能使您能够为文档中的字段创建独特的访问和值定义逻辑。

虚拟属性是文档的属性,它们是根据其他字段的数据动态计算而来,但不存储在数据库中。使用 "virtual" 方法,您可以在 Mongoose 模式中定义虚拟属性。

以下是使用虚拟属性在 Mongoose 中更改字段的示例:

const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
  firstName: String,
  lastName: String
});

// 为全名定义一个虚拟属性
userSchema.virtual('fullName').get(function() {
  return `${this.firstName} ${this.lastName}`;
}).set(function(fullName) {
  const [firstName, lastName] = fullName.split(' ');
  this.firstName = firstName;
  this.lastName = lastName;
});

const User = mongoose.model('User', userSchema);

// 创建一个新用户
const user = new User({ firstName: 'John', lastName: 'Doe' });

console.log(user.fullName); // 输出: "John Doe"

user.fullName = 'Jane Smith';
console.log(user.firstName); // 输出: "Jane"
console.log(user.lastName); // 输出: "Smith"

在上面的示例中,字段 firstNamelastName 被合并为一个名为 fullName 的虚拟属性。当获取 fullName 时,会使用 get 函数,而当设置 fullName 时,会使用 set 函数。

Getter 和 Setter
或者,您可以直接使用 getter 和 setter 来更改 Mongoose 模式中的字段。您可以使用 getter 和 setter 来创建自己的字段访问和设置逻辑。

以下是 Mongoose 如何使用 getter 和 setter 的示例:

const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
  firstName: String,
  lastName: String
});

// 为全名字段定义 getter 和 setter
userSchema.path('firstName').get(function(value) {
  return value.charAt(0).toUpperCase() + value.slice(1);
}).set(function(value) {
  return value.trim();
});

const User = mongoose.model('User', userSchema);

// 创建一个新用户
const user = new User({ firstName: '  john', lastName: 'doe  ' });

console.log(user.firstName); // 输出: "John"

user.firstName = '  jane  ';
console.log(user.firstName); // 输出: "Jane"

在上面的示例中,我们为 firstName 字段定义了一个 getter 和 setter。setter 会删除 firstName 值中的前导和尾随空格,而 getter 会将值的第一个字符大写。

虚拟属性和 getter/setter 都使 Mongoose 用户能够编辑字段,而不实际更改后端逻辑。根据您的应用程序的特定需求,选择最适合您需求的策略。

英文:

You can use virtual properties, getters, and setters in your schema definition to modify fields in a Mongoose schema without using backend code. These enable you to create unique access and value definition logic for fields in your documents.

Virtual properties are those of a document that are computed on-the-fly using data from other fields but are not stored in the database. Using the 'virtual' method, you can define virtual properties in your Mongoose schema.

Here is an illustration of how to change fields in Mongoose using virtual properties:

<!-- language: lang-js -->

const mongoose = require(&#39;mongoose&#39;);
const userSchema = new mongoose.Schema({
firstName: String,
lastName: String
});
// Define a virtual property for the full name
userSchema.virtual(&#39;fullName&#39;).get(function() {
return `${this.firstName} ${this.lastName}`;
}).set(function(fullName) {
const [firstName, lastName] = fullName.split(&#39; &#39;);
this.firstName = firstName;
this.lastName = lastName;
});
const User = mongoose.model(&#39;User&#39;, userSchema);
// Create a new user
const user = new User({ firstName: &#39;John&#39;, lastName: &#39;Doe&#39; });
console.log(user.fullName); // Output: &quot;John Doe&quot;
user.fullName = &#39;Jane Smith&#39;;
console.log(user.firstName); // Output: &quot;Jane&quot;
console.log(user.lastName); // Output: &quot;Smith&quot;

<!-- end snippet -->

In the aforementioned example, the fields firstName and lastName are combined into a virtual property called fullName. When fullName is being retrieved, the get function is used, and when it is being set, the set function is used.

Putters and Takers
Alternately, you can directly alter fields in your Mongoose schema by using getters and setters. You can create your own logic for field access and setting by using getters and setters.

Here is an illustration of how Mongoose uses getters and setters:

<!-- language: lang-js -->

const mongoose = require(&#39;mongoose&#39;);
const userSchema = new mongoose.Schema({
firstName: String,
lastName: String
});
// Define a getter and setter for the full name
userSchema.path(&#39;firstName&#39;).get(function(value) {
return value.charAt(0).toUpperCase() + value.slice(1);
}).set(function(value) {
return value.trim();
});
const User = mongoose.model(&#39;User&#39;, userSchema);
// Create a new user
const user = new User({ firstName: &#39;  john&#39;, lastName: &#39;doe  &#39; });
console.log(user.firstName); // Output: &quot;John&quot;
user.firstName = &#39;  jane  &#39;;
console.log(user.firstName); // Output: &quot;Jane&quot;

<!-- end snippet -->

For the firstName field, we define a getter and setter in this example. The setter removes any leading or following whitespace from the firstName value and the getter capitalizes the first character of the value.

Both virtual properties and getters/setters give Mongoose users the ability to edit fields without actually changing the backend logic. Based on the particular demands of your application, select the strategy that best meets your needs.

huangapple
  • 本文由 发表于 2023年8月10日 15:20:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76873434.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定