Using Mongoose's findAndUpdate method along with discriminators

My inventory consists of various products like smartphones, laptops, headphones, etc. However, in the end, all these products are represented as a single generalized ProductsModel

ProductsModel

import { Schema, model } from 'mongoose'

export const productsDiscriminatorKey = 'productKind'

const ProductsSchema = new Schema(
    {
        name: { type: String },
    },
    { productsDiscriminatorKey, timestamps: true }
)

export default model('Products', ProductsSchema)

PhoneModel

import mongoose, { Schema } from 'mongoose'

import ProductsModel, { productsDiscriminatorKey } from './ProductsModel.js'

const PhoneSchema = new Schema(
    {
        name: { type: String, required: true },
        price: { type: String, required: true },
        color: { type: String, required: true },
        memory: { type: String, required: true },
        screen: { type: String, required: true },
        fps: { type: String, required: true },
        sim: { type: String, required: true },
        preview: { type: String, required: true },
        images: [{ type: String, required: true }],
        category: {
            type: mongoose.Schema.ObjectId,
            ref: 'Category',
        },
        type: {
            type: mongoose.Schema.ObjectId,
            ref: 'Type',
        },
        count: { type: Number },
    },
    { productsDiscriminatorKey }
)

const PhoneModel = ProductsModel.discriminator('Phones', PhoneSchema)
export default PhoneModel

I have implemented a method for removing products from the database based on quantity rather than deleting the entire model at once. The logic works correctly when used in specific models like PhoneModel, but not when tried from ProductsModel. The count field remains unchanged.

Delete logic

    async delete(req, res) {
        try {
            const { id } = req.params
            const { count } = req.body

            const candidate = await ProductsModel.findById(id)

            if (candidate.count < count) {
                return res.status(500).json({ message: 'More than count in base' })
            }

            if (candidate.count === count || !count) {
                await ProductsModel.findByIdAndDelete(id)
                return res.status(200).json({ message: 'All deleted' })
            }

            if (candidate.count > count) {
                await ProductsModel.findByIdAndUpdate({ _id: id }, { count: candidate.count - count })

                return res.status(200).json({ message: `${count} successfully deleted` })
            }
        } catch (error) {
            return res.status(500).json({ message: 'Server error' })
        }
    }

In certain scenarios, only a specific quantity (count) needs to be deleted and not all at once. This is achieved by adjusting the count field using findByIdAndUpdate. Despite implementing this logic, it does not function as expected without any error messages.

Answer №1

There is an issue because the base schema does not have access to keys in an inherited schema. The problem arises when the base schema attempts to retrieve the key count from the inherited schema. In this scenario, ProductsModel represents the base schema and PhoneModel represents the inherited schema. The key 'count' belongs to the PhoneModel schema and not the ProductsModel schema. As a result, Mongoose will disregard the update document { count: candidate.count - count }.

await ProductsModel.findByIdAndUpdate({ _id: id }, { count: candidate.count - count })

On the other hand, queries that involve the key _id work correctly since it exists in both schemas.

const candidate = await ProductsModel.findById(id)
await ProductsModel.findByIdAndDelete(id)

The provided code showcases this issue with references to line 1, line 2, and line 3. Verification of these lines confirms that the base schema lacks access to keys in an inherited schema.

const mongoose = require('mongoose');
const { Schema } = mongoose;
const asserts = require('assert');

const options = { discriminatorKey: 'kind' };

const parentSchema = new Schema({ parentkey1: String }, options);
const Parent = mongoose.model('Parent', parentSchema);

const childSchema = new Schema({ childkey1: String }, options);
const Child = Parent.discriminator('Child', childSchema, options);

let parentdoc = new Parent({
  parentkey1: 'parentkey1',
});

let childdoc = new Child({
  parentkey1: 'parentkey1',
  childkey1: 'childkey1',
});

// document objects
asserts.ok(parentdoc._id);
asserts.ok(childdoc._id);

asserts.ok(parentdoc.parentkey1);
asserts.ok(!parentdoc.childkey1);  // line 1
asserts.ok(childdoc.parentkey1);
asserts.ok(childdoc.childkey1);

run().catch((err) => console.log(err));
async function run() {
  await mongoose.connect('mongodb://127.0.0.1:27017/test');
  await Parent.deleteMany();
  await Child.deleteMany();
  await parentdoc.save();
  await childdoc.save();

  parentdoc = await Parent.findById(parentdoc._id);
  childdoc = await Child.findById(childdoc._id);

  asserts.ok(parentdoc._id);
  asserts.ok(childdoc._id);

  asserts.ok(parentdoc.parentkey1);
  asserts.ok(!parentdoc.childkey1); // line 2
  asserts.ok(childdoc.parentkey1);
  asserts.ok(childdoc.childkey1);

  parentdoc = await Parent.findByIdAndUpdate(parentdoc._id, {
    childkey1: 'new value',
  });
  asserts.ok(parentdoc.parentkey1);
  asserts.ok(!parentdoc.childkey1);  // line 3
}

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

PHP-generated AngularJs Select Element

I'm facing an issue with my PHP function in my AngularJS application. I have created a function to select a default option, but it's not displaying the desired value. Here is the function code: function qtyList($selectName, $selectQty){ $st ...

Ways to troubleshoot and fix the problem of encountering an "Internal Server Error" when sending emails with nodeMailer in node.js

When attempting to send a confirmation email using nodemailer, I encountered an internet server error in production when allowing insecure apps for Gmail accounts, although it works fine locally. Any suggestions on how to resolve this issue? router.post(& ...

The Protractor tool (node:9208) threw an UnhandledPromiseRejectionWarning due to an ElementNotVisibleError, indicating that the element is not interactable. Despite this

I am attempting to interact with an element using protractor but encountering the following error (node:9208) UnhandledPromiseRejectionWarning: ElementNotVisibleError: element not interactable (Session information: chrome=69.0.3497.92) (Driver informa ...

"How to change the hover background of a select element in Chrome from its default setting to something else

https://i.sstatic.net/G2deM.png Is there a way to remove the background color on hover and replace it with a different color? .drp-policydetails { border: 1px solid #dddddd; background-color: #ffffff; } <div className="form-group"> <sele ...

The body onload function fails to run upon the page loading

I'm having trouble with my body onload function not executing. When I load the page, I want to display all records that are selected in the drop_1 dropdown and equal to ALL. I have a script that sends values q and p to getuser.php. The values sent are ...

How to fetch all records from every collection in a MongoDB database using PyMongo

I have a Mongo database named mydbase that contains various collections such as coll1, coll2, and coll3. My goal is to gather all the documents from each collection and structure them in a list of lists using PyMongo. I attempted the following code: [list ...

Managing multiple session IDs in ExpressorDealing with dual session

I encountered a situation where: After logging into access.abc.com, I received a cookie named connect.sid with domain as .abc.com Then, on the same browser, I logged into xyz.abc.com and received another session cookie with the same name but a differ ...

Combining PageObjects with non-angular pages: is it possible?

I am currently working on writing protractor tests for our application. One specific challenge I have encountered is dealing with a non-angular page within an angular page as an iframe. The issue I am facing is that I cannot properly map fields from the n ...

Vue.js - Capturing a scroll event within a vuetify v-dialog component

Currently, I am working on a JavaScript project that involves implementing a 'scroll-to-top' button within a Vuetify v-dialog component. The button should only appear after the user has scrolled down by 20px along the y-axis. Within the v-dialog, ...

Unlocking the power of RXJS by de-nesting subscriptions

Trying to resolve the nested subscription issue has become a time-consuming puzzle. I've experimented with mergeMap, flatMap, and switchMap without success. Unfortunately, the examples I've come across don't quite fit my needs, leaving me wi ...

Waiting for user submission before executing a JavaScript function

const onSubmit = ()=>{ someFunction().then(()=>{ // next step is to wait for user interaction by clicking a specific button // user initiates the action // perform specific task }) } Essentially, after the initial form submissi ...

Tips on navigating an array to conceal specific items

In my HTML form, there is a functionality where users can click on a plus sign to reveal a list of items, and clicking on a minus sign will hide those items. The code structure is as follows: <div repeat.for="categoryGrouping of categoryDepartm ...

Trying to retrieve a CSS property using jQuery

Having trouble retrieving the correct CSS value for a background using a spectrum.js color picker. No matter which color is chosen, rgba(0,0,0,0) is always selected. Strangely enough, when checking the background in the console, it shows up correctly in th ...

AngularJS implementation for a confirmation dialog with data

I need help creating a confirmation dialog box for user action verification. Here's the situation: I have a table with multiple events, and users can choose to delete an event. This is how the table is structured: <tbody> <tr ng-repeat= ...

Text located in the bottom right corner of the window with the use of JavaScript

Is there a way to replace text at the bottom right of the window, as opposed to the page, so that it remains fixed in the corner of the window? I'm looking to create a "share" link that is always visible. ...

Strategies for addressing the issue of socket.io being undefined in app.js

My dilemma lies in the separation of my express app logic and the instantiation of the express server. I am encountering difficulties accessing socket.io within my app file. Should I consolidate the socket.io implementation into index.js or is there a way ...

How can I choose records from collection 'x' in mongodb?

I need to fetch all fields from my database using an API call Here is my code: exports.objfields = async (req, res, next) => { try { var db = mongo.connection; var objeto = req.headers.objeto; const result = db.db.collection(objeto).find( ...

I am having issues with the Load More Posts Ajax Button on my WordPress site and it is

I'm trying to display more posts when a button is clicked. Upon inspecting and checking the network, everything seems to be working fine, or at least that's what I assume. https://i.sstatic.net/44VS1.jpg https://i.sstatic.net/KEkiz.jpg I&apos ...

Extracting over 100 tweets from the Twitter API with the help of Node.js

I am facing a challenge while trying to fetch over 100 tweets from Twitter in nodejs as I continuously receive an empty array. Here is the approach I have attempted: const MAX_TWEETS = 200; const TWEETS_PER_REQUEST = 100; async function retrieveTweets(T, ...

Error message: "SyntaxError: Unexpected token import was not caught by the foundation"

I have recently taken over development from a previous developer who integrated Zurb Foundation as a framework into our website. The Foundation framework was installed using npm. I am encountering errors in the console related to all of the foundation java ...