Node.js Mongoose:Need.pre-hook递归删除树中的子对象
我在Mongoose中定义了一个模式,它构成了一个非常有效的递归树结构。每个节点都有一个子节点数组,这些子节点引用同一树和架构中的子节点。树可以通过子对象中的递归深入 我想使用Mongoose.pre()中间件hook递归删除子节点(及其所有子节点),当我使用其他Mongoose调用删除它们的父节点时 我尝试了以下代码的变体,但由于各种错误而失败-最新的错误“baustoff(remove)不是运行时的函数”记录在下面代码的注释中 我的问题是: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调用
- 在.pre函数中首先发出哪个Mongoose调用
- 如何正确处理儿童数组
- 注意:下面代码中的当前deleteMany至少会将其放入该函数的内部,如日志所示,但可能仍然是错误的
- 如何递归获取删除的所有子项的调用。。。孩子们
- 在.pre结尾调用什么以使其正常工作?当前引发错误的位置是哪里
// 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。有人有这方面的代码片段吗?