When an express pre-remove signal initiates another pre-remove action during the removal process

Imagine having 4 different models structured like this:

┌────────────┐      ┌────────────┐
│    User    │      │    Goal    │
├────────────┤ 1    ├────────────┤ 1
│    _id     │◄──┐  │    _id     │◄──┐
└────────────┘   └──┤  ref_user  │   │
                1..*└────────────┘   │
                                     │
┌───────────┐     ┌───────────────┐  │
│   Date    │     │     Data      │  │
├───────────┤ 1   ├───────────────┤  │
│ _id: date │◄─┐  │     _id       │  │
└───────────┘  └──┤    ref_date   │  │
                1 │    ref_goal   ├──┘
                  └───────────────┘ *

The scenario involves a pre remove operation that automatically deletes associated dates when removing data.

DataSchema.pre('remove', async function (next) {
    try {
        await DateModel.findByIdAndRemove(this.ref_date);
        console.log("Date removed");
        next();
    } catch (err) {
        console.log(err);
        next(err);
    }
});

An issue arises when deleting a goal, where all associated data should be deleted as well. The expected behavior is that the pre remove hook in Data should trigger upon removal of data caused by another pre remove hook. However, this does not occur currently.

Although it is possible to retrieve an array of Data from Goal and individually delete dates, there may be a more efficient approach.

Is there a method to prompt the pre-remove action in Data from the pre-remove event in Goal? Alternatively, is there a way to delete all Dates from an array of Data?

Note: Similar functionality will be required for user deletion in the future (removing goals, then data and dates).

Edit:

Provided below is the pre-remove hook for Goal:

GoalSchema.pre('remove', async function (next) {
    try {
        await DataModel.deleteMany({ 'ref_goal': this._id });
        console.log("Data removed");
        next();
    } catch (err) {
        console.log(err);
        next(err);
    }
});

Attempts with methods like deleteMany or remove have not successfully triggered the pre-remove hook in Data.

Environment:

"express": "^4.17.1",
"mongoose": "^5.12.2",

Answer №1

There seem to be a couple of issues in your code that need to be addressed:

  1. The problem lies in the discrepancy between registering a remove hook on the data schema:

    DataSchema.pre('remove', ...)
    

    and the fact that the callback function for the goal's remove hook triggers a deleteMany middleware:

    await DataModel.deleteMany(...)
    

    This mismatch prevents the execution of the data's remove hook.

    Additionally, you mentioned testing other functions like remove, leading us to the second issue:

  2. The registration of remove hooks is applied to documents by default, but you're executing functions on models instead.

    Refer to this note in the documentation:

    Note: By specifying schema.pre('remove'), Mongoose will register this middleware for doc.remove() by default. To run your middleware on Query.remove(), use

    schema.pre('remove', { query: true, document: false }, fn)
    .

    It's also crucial to consider this explanation:

    You can provide options to Schema.pre() and Schema.post() to switch Mongoose calls between Document.remove() and Model.remove(). Ensure both document and query properties are set in the object passed:

    // Document middleware only 
    schema.pre('remove', { document: true, query: false }, function() {   
       console.log('Removing doc!'); 
    });
    
    // Query middleware only; triggered by `Model.remove()` not `doc.remove()`
    schema.pre('remove', { query: true, document: false }, function() {  
       console.log('Removing!'); 
    });
    

To correct these issues, I suggest the following approach:

const onRemoveData = async function (next) {
   try {
        let removed = [this];
        if (this instanceof mongoose.Query) {
           removed = await this.model.find(this.getQuery());
        }
        removed.forEach(async function(doc) {
            await DateModel.findByIdAndRemove(doc.ref_date);
            console.log("Date removed");
        });
        next();
    } catch (err) {
        console.log(err);
        next(err);
    }
}
DataSchema.pre(['remove', 'deleteMany'], { document: true, query: false}, onRemoveData);
DataSchema.pre(['remove', 'deleteMany'], { document: false, query: true}, onRemoveData);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Generating a download link with an expiration feature in node.js or express for both frontend and backend operations

Hello everyone, I'm a beginner here and have recently started working with node.js and express.js. I am looking to implement a download link on my website that expires after a certain time, but I've been struggling with the code for about a week ...

How can you access the query in Next.js API when req.query is initially set to undefined?

Is there a way to compare the value of req.query with the cookies on the site, even when req.query is undefined upon initial load? How can this be addressed? export default async function handler(req, res) { const { method } = req; const userId = req ...

There seems to be an issue with AJAX file uploading functionality in Django

I'm facing an issue with uploading files using the onchange event and AJAX. I am only able to get the file path on the backend, not the actual file itself. My goal is to modify the code so that when a PDF file is selected, it automatically gets upload ...

How can you refresh the .replaceWith method in jQuery?

Is there a way to reset the .replaceWith function so that the html, css and javascript elements are restored to their original state? I am looking to have an icon replace the text when the user clicks on "contact", and then have the text return when the u ...

Unable to successfully download zip files using Ajax in the MVC framework

I need to trigger the download of a zip file that contains .pdf files using an ajax call. The issue I'm encountering is that everything seems to be working fine except for the actual downloading of the zip file. public FileResult DownloadZip(string[] ...

Using (javascript:) within Href attributes

Recently, I've noticed some people including "javascript:" in the href attribute of an a tag. My question is: what is the purpose of this? Does it guarantee that clicking on the a tag directs the function of the click to JavaScript for handling, rathe ...

Issue: The npm module 'moment' cannot be located

My Meteor app works flawlessly on localhost, but when deployed to a remote heroku server, I encounter these errors. (I am following this) Any suggestions on how to resolve this issue? 2016-09-09T13:26:02.533532+00:00 heroku[web.1]: Starting process with ...

To ensure that the date variable is updated daily at midnight on a Node.js Express server, allowing it to fetch data from a new collection called `

I am managing an express server where I am required to retrieve a new collection from Firebase that follows the format data-${date}. How can I effectively utilize node schedule or any other method in order to achieve this task? The code primarily looks li ...

AngularJS's ng-click function seems to be malfunctioning

Currently, I am in the process of learning angularJS with the help of the book titled "Learning Web Development with Bootstrap and AngularJs." One challenge I am facing is creating a ng-click functionality for a button in my project. Unfortunately, when I ...

The Prometheus metrics are not functioning properly with a custom node.js application

While following some tutorials, I noticed that they all include the 'prom-client' and create a new /metrics URL in the same way. However, when I try to access my http://localhost:4000/metrics, instead of seeing my metrics, I encounter the followi ...

Modifying JavaScript object values using the Object() constructor

My background is in Groovy, which has similar syntax to JavaScript. In Groovy, I can easily copy values from one map to another like this: def myMap1 = {}; def myMap2 = {}; myMap1["key1"] = "value1"; myMap1["key2"] = "value2"; myMap1["key3"] = "value3"; ...

Error Alert: React Hook ReferenceError - Attempting to access 'variable name' prior to initialization - Issue detected in [React Hook]

Recently, I've started diving into the world of React. My current challenge involves building a table that holds an array of data. To populate this table, I'm utilizing the set method to extract specific values from a multi-dimensional array. For ...

Secure your API routes in NextJS by using Passport: req.user is not defined

Currently, I am utilizing NextJS for server-side rendering and looking to secure certain "admin" pages where CRUD operations on my DB can be performed. After successfully implementing authentication on my website using passport and next-connect based on a ...

Implementing conditional rendering using custom division return functions with onClick attribute on a submit button in React: A step-by-step guide

import React from "react"; class Input extends React.Component { constructor() { super(); this.state = { phone: "", weight: "", height: "", gender: "", smoke: "", lazy: "", bmi: "", pain: "", ...

Developing a unique bundle with tailored elements

I am interested in developing a custom Material UI component and making it available as a standalone package within my company's private NPM repository. Specifically, I have customized the Date Picker to create a Date Range Picker since Material UI d ...

The parameter label is being detected as having an any type, as specified in the Binding element 'label'

Currently, I am referencing an example code snippet from react-hook-form. However, upon implementation, I encounter the following error: (parameter) label: any Binding element 'label' implicitly has an 'any' type.ts(7031) The example c ...

What is the process for transforming information from a URL/API into a table in a node.js express application with jade?

I have attempted the following code in my index.js file: var express = require('express'); var router = express.Router(); var request = require('request'); /* GET home page. */ router.get('/', function(req, res, next) { r ...

Unable to run the method in the parent component from the child component

I am attempting to trigger a method to run on a parent component when a button within one of its child components is clicked. I am utilizing single file components with Webpack. Below is the code for the child component: <template> <button v-on ...

Is it recommended to utilize Req.app.locals to save flash messages?

Would it be considered safe to utilize req.app.locals for storing req.flash messages? (especially when using connect-flash) After conducting some research and running tests, my understanding is that req.app.locals is a global variable rather than user-spe ...

What is the reason for typescript's lack of a "function" type?

As a newcomer to TypeScript, I'm puzzled as to why I am unable to define an object like this: const obj: { property1: string property2: boolean property3: function } It seems that the only workaround is to use: const obj: { property1: strin ...