Node.js Mongoose:Need.pre-hook递归删除树中的子对象

Node.js Mongoose:Need.pre-hook递归删除树中的子对象,node.js,mongodb,recursion,mongoose,tree,Node.js,Mongodb,Recursion,Mongoose,Tree,我在Mongoose中定义了一个模式,它构成了一个非常有效的递归树结构。每个节点都有一个子节点数组,这些子节点引用同一树和架构中的子节点。树可以通过子对象中的递归深入 我想使用Mongoose.pre()中间件hook递归删除子节点(及其所有子节点),当我使用其他Mongoose调用删除它们的父节点时 我尝试了以下代码的变体,但由于各种错误而失败-最新的错误“baustoff(remove)不是运行时的函数”记录在下面代码的注释中 我的问题是: 在.pre函数中首先发出哪个Mongoose调用

我在Mongoose中定义了一个模式,它构成了一个非常有效的递归树结构。每个节点都有一个子节点数组,这些子节点引用同一树和架构中的子节点。树可以通过子对象中的递归深入

我想使用Mongoose.pre()中间件hook递归删除子节点(及其所有子节点)
,当我使用其他Mongoose调用删除它们的父节点时

我尝试了以下代码的变体,但由于各种错误而失败-最新的错误“baustoff(remove)不是运行时的函数”记录在下面代码的注释中

我的问题是:

  • 在.pre函数中首先发出哪个Mongoose调用
  • 如何正确处理儿童数组

  • 注意:下面代码中的当前deleteMany至少会将其放入该函数的内部,如日志所示,但可能仍然是错误的

  • 如何递归获取删除的所有子项的调用。。。孩子们

  • 在.pre结尾调用什么以使其正常工作?当前引发错误的位置是哪里

注意:另外两个用于删除父节点的Mongoose调用(此模型代码之外)应该触发上面定义的.pre钩子。这两个方面的代码片段是:

1) 等待Baustoff.remove({});-->这将在测试开始时清空我的数据库,并导致.pre代码出现错误“baustoff(remove)在运行时不是函数”

2) Baustoff.findOneAndDelete(req.params.baustoffId)-->尚无法测试此项,因为.pre hook已在1)中抛出错误

有猫鼬经验的人能帮我得到这个吗。预编码正确吗?我在新代码部分中肯定有一个或多个错误。提前谢谢你处理我的问题

// baustoff.model.js
  const mongoose        = require('mongoose');                    
  const Baustoffe       = require('./../../baustoffe');           // for some enums, irrelevant for BaustoffSchema.pre('remove', )
  const BaumKnotenTypen = require('./../../baumknotentypen');     // for some enums, irrelevant for BaustoffSchema.pre('remove', )             
  const VerzweigungsTypen = require('./../../verzweigungstypen'); // for some enums, irrelevant for BaustoffSchema.pre('remove', )              
  const MaterialEigenschaftSchema  = require('./materialeigenschaft.model.js').model('MaterialEigenschaft').schema 
  const Schema = mongoose.Schema;
  let BaustoffSchema = new Schema  

  ({
    // First some normal properties in my BaustoffSchema schema:
    kurzBezeichnung: { type: String },                                        
    bezeichnung:     { type: String, enum: Object.values(Baustoffe) },       
    baumKnotenTyp:   { type: String, enum: Object.values(BaumKnotenTypen) }, 
    verzweigungsTyp: { type: String, enum: Object.values(VerzweigungsTypen)}, 
    aktiv:           { type: Boolean, default: true},                        
    produkt:         {type: String},
    materialEigenschaften: [MaterialEigenschaftSchema], // some properties as an array to allow variable number of props
    /*--------------------------------------------------------------------*/
    // Now an array of references to children that make up a tree structure, as they refer recursively to the model 'Baustoff' 
    kinder:          [{ type: Schema.Types.ObjectId, ref: 'Baustoff' }],      
   },
         {}
   );
   Object.assign(BaustoffSchema.statics, {Baustoffe},{BaumKnotenTypen},{VerzweigungsTypen} ); 
    // Above line is to define some statics, irrelevant for the .pre function
    /*--------------------------------------------------------------------*/
    // PROBLEMATIC PART starts here:
    // Goal: Define a  Mongoose BaustoffSchema.pre() hook that recursively deletes all children further down in the tree, when their parent is deleted

    BaustoffSchema.pre('remove', {query: true}, function(next){
    mongoose.models["Baustoff"].deleteMany({ kinder: this._id }, function(err, baustoff) {
         console.log("In Mongoose pre Hook before if");
         if(baustoff) {
             console.log("In Mongoose pre Hook after if");
             baustoff.remove(); // ERROR is thrown HERE with this variant of the code: baustoff.remove is not a function at runtime !!!!!!!!!!
          });
          next();
      }); // end of .pre hook
  let Baustoff = mongoose.model('Baustoff', BaustoffSchema, 'Baustoffe'); // Model Name, Schema Name, Collection Name in Mongo db
  module.exports = Baustoff; // Baustoff is model name hook

我实现了一个变通方法,正如我在上一篇评论中所指出的。我并不完全满意它,因为它没有像最初所希望的那样使用Mongoose.pre中间件,而是使用“常规”代码在删除树节点之前删除所有子节点(+=子节点)

如果有人知道如何使用.pre中间件实现同样的功能,我很乐意将其作为首选解决方案!我也希望您能告诉我。pre是否适合此要求

我知道有更复杂的解决方案来处理树,比如物化路径模式,但请注意,目前我只寻找不会改变Mongoose模式的解决方案

下面是我的初始代码,用于“定期”删除要在树中删除的父节点的所有子节点。它使用一个临时的_id堆栈来处理递归。我相信它可以进一步完善:

async function subTreeDelete() {

var descendants = []; // Array to collect all children++, to delete them jointly after the collection phase
var stack = []; // Auxiliary array to recursely collect children that still need to be traversed
const node_id = req.params.baustoffId; // _id of parent node to be deleted, from REST call
var item = await Baustoff.findOne({ _id: node_id }).exec(); // Using await, therefore everything put into an async function
console.log("In Delete children, find parent: ", item); 
stack.push(item); // The parent needs to be traversed first, put it on stack

while (stack.length > 0) {
  var currentnode = stack.pop(); // Get a node from stack, as long as stack isn't empty
  var children = await Baustoff.find({_id: { $in: currentnode.kinder }}).exec(); // Find node's children
  console.log("In Delete children, children: ", children); // Using await, therefore everything put into an async function
  children.forEach(child => {
    descendants.push(child._id); // Push all _ids of direct children on our descendants array that collects the children++
    if (child.kinder.length > 0) {
      stack.push(child); // child node has children still to be traversed, push it on stack
    }
  });
}
console.log("In Delete children: Collected all children of children: ", descendants);
await Baustoff.deleteMany({ _id: { $in: descendants } }).exec(); // Now delete all children++ as collected in descendants
} // /async function

subTreeDelete(); // Call the above async funktion, to delete all children++
// Now we are finally ready to delete the parent node....code for that not included here

我实现了一个变通方法,正如我在上一篇评论中所指出的。我并不完全满意它,因为它没有像最初所希望的那样使用Mongoose.pre中间件,而是使用“常规”代码在删除树节点之前删除所有子节点(+=子节点)

如果有人知道如何使用.pre中间件实现同样的功能,我很乐意将其作为首选解决方案!我也希望您能告诉我。pre是否适合此要求

我知道有更复杂的解决方案来处理树,比如物化路径模式,但请注意,目前我只寻找不会改变Mongoose模式的解决方案

下面是我的初始代码,用于“定期”删除要在树中删除的父节点的所有子节点。它使用一个临时的_id堆栈来处理递归。我相信它可以进一步完善:

async function subTreeDelete() {

var descendants = []; // Array to collect all children++, to delete them jointly after the collection phase
var stack = []; // Auxiliary array to recursely collect children that still need to be traversed
const node_id = req.params.baustoffId; // _id of parent node to be deleted, from REST call
var item = await Baustoff.findOne({ _id: node_id }).exec(); // Using await, therefore everything put into an async function
console.log("In Delete children, find parent: ", item); 
stack.push(item); // The parent needs to be traversed first, put it on stack

while (stack.length > 0) {
  var currentnode = stack.pop(); // Get a node from stack, as long as stack isn't empty
  var children = await Baustoff.find({_id: { $in: currentnode.kinder }}).exec(); // Find node's children
  console.log("In Delete children, children: ", children); // Using await, therefore everything put into an async function
  children.forEach(child => {
    descendants.push(child._id); // Push all _ids of direct children on our descendants array that collects the children++
    if (child.kinder.length > 0) {
      stack.push(child); // child node has children still to be traversed, push it on stack
    }
  });
}
console.log("In Delete children: Collected all children of children: ", descendants);
await Baustoff.deleteMany({ _id: { $in: descendants } }).exec(); // Now delete all children++ as collected in descendants
} // /async function

subTreeDelete(); // Call the above async funktion, to delete all children++
// Now we are finally ready to delete the parent node....code for that not included here

我将引发代码中标记的错误的行更改为:Baustoff.remove({u-id:this.\u-id}).exec();/仅适用于架构名称!!这将导致.pre hook中的无限循环!这让我相信,一种解决方法可能是使用递归代码遍历所有子节点,将所有子节点推送到一个临时数组,最后删除该数组中的所有ID。有人有这方面的代码片段吗?我将引发代码中标记的错误的行更改为:Baustoff.remove({u-id:this.\u-id}).exec();/仅适用于架构名称!!这将导致.pre hook中的无限循环!这让我相信,一种解决方法可能是使用递归代码遍历所有子节点,将所有子节点推送到一个临时数组,最后删除该数组中的所有ID。有人有这方面的代码片段吗?