How to delete a single item from an array using MongoDB

For my discord bot, I've implemented a purchasing system that adds items to the inventory array in mongoDB like this:

data.Inventory[itemTobuy] ++;

The stored format looks like this:

pizza: 1

I also have a system in place where users can use items from their inventory. I want to remove the item entirely if there's only one instance of it, but if there are multiple instances, I want to decrement the value by one, for example, from pizza: 5 to pizza: 4. Although, I'm only about 25% sure on how to accomplish this.

The following is the full code for the command that adds the item if necessary:

const { Client, Message, MessageEmbed } = require('discord.js');
const { User } = require("../../databasing/schemas/User")
const inventory = require('../../databasing/schemas/inventory')
const items = require('../../items/shopItems')

module.exports = {
    name: 'buy',
    /** 
     * @param {Client} client 
     * @param {Message} message 
     * @param {String[]} args 
     */
    run: async(client, message, args) => {
        userData = await User.findOne({ id: message.author.id }) || new User({ id: message.author.id })
        const itemTobuy = args[0].toLowerCase()
        embed = new MessageEmbed({ color: "#2F3136" })
        if(!args[0]) return message.channel.send({
            embeds: [ embed.setTitle('<:redCross:1004290018724020224> | Please mention something to buy!')]
        });
        const itemid = !!items.find((val) => val.item.toLowerCase() === itemTobuy);
        if(!itemid) return message.channel.send({
            embeds: [ embed.setTitle(`<:redCross:1004290018724020224> | ${itemTobuy} is not a valid item!`)]
        });
        itemPrice = items.find((val) => val.item.toLowerCase() === itemTobuy).price;
        userBalance = userData.wallet;
        if(userBalance < itemPrice) return message.channel.send({
            embeds: [embed.setTitle(`<:redCross:1004290018724020224> | You dont have enough money to buy this item(LOL)`)]
        }); 
        const param ={
            User: message.author.id
        }
        inventory.findOne(param, async(err, data) => {
            if(data){
                const hasItem = Object.keys(data.Inventory).includes(itemTobuy);
                if(!hasItem){
                    data.Inventory[itemTobuy] = 1;
                } else {
                    data.Inventory[itemTobuy] ++;
                }
                await inventory.findOneAndUpdate(param, data);
                } else {
                new inventory({
                    User: message.author.id,
                    Inventory: {
                        [itemTobuy]: 1,
                    }
                }).save()
                }
                message.channel.send({
                    embeds: [embed.setTitle(`<:greenTick:1004290019927785472> | Successfully bought ${itemTobuy}!`)]
                });
                userData.wallet -= itemPrice;
                userData.save()
        })
    }
}

Answer №1

If you want to reduce the value of your item, you can utilize the $inc method. Here's an example:

const param = {
  User: message.author.id
}

const item_name = args.splice(0).join(" ").toLowerString();
//Please note that .toLowerString() will convert any string to lowercase.
//If case sensitivity is important, omit the .toLowerString().

inventory.findOne({
   param, //User.id
   "Inventory.name": item_name //Modify the "name" based on how you reference your item names.
}, async(err, data) => {
   //We are checking for item existence here.
  if(data) {
    //Reduce the item quantity here.
    await inventory.findOneAndUpdate({
      param,
      "Inventory.name": item_name
    }, {
       $inc: {
         "Inventory.$.value": -1 //Adjust based on how you represent item values.
       }
    })
  } else {
    //Send a message if the item doesn't exist.
  }
})

UPDATE:

To retrieve the name and value of your item, you must search for the specific item name.

Begin by setting up your inventory as an array.

const inv = await inventory.findOne({
  param
})

const arr = inv.Inventory;

const arr = inv.Inventory; converts it into an array. Next, locate the name.

const item_name = args.splice(0).join(" ").toLowerString();
const inv = await inventory.findOne({
  param
})

const arr = inv.Inventory;
const item = arr.find(x => x.name == item_name);

Once you have the item_name, you can display the value and name wherever you choose, whether in an embed or a regular message.

const item_name = args.splice(0).join(" ").toLowerString();
const inv = await inventory.findOne({
  param
})

const arr = inv.Inventory;
const item = arr.find(x => x.name == item_name);

const items_value = item.value;
const items_name = item.name;

const embed = new MessageEmbed()
.addFields(
  {name: `Name:`, value: `${items_name}`},
  {name: `Value:`, value: `${items_value}`}
)

message.channel.send({embeds: [embed]})

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

Is it true that by utilizing Vue's v-for, every line of HTML code becomes a

I'm struggling to utilize v-for in order to create multiple div elements, but no matter how I attempt it (even trying to iterate over a list), the v-for doesn't seem to function properly and always turns the line into a comment when executed. No ...

Send the values of the form variables as arguments

I am trying to integrate a webform (shown below) with a function that passes form variables. Once the user clicks submit, I want the username and password to be passed into a website login function: $.ajax( { url: "http://microsubs.risk.ne ...

Troubleshooting module not being found with rekuire, requirish, or rfr in resolving relative require problem in nodejs

Looking to steer clear of the complicated relative path problem detailed here by opting for one of the suggested solutions. I've found three similar libraries that could help: rekuire node-rfr aka Require from Root requirish I've experimented ...

Having trouble removing a cookie in express?

Seems pretty straightforward. In the /user/login route, I set a cookie as shown below: if (rememberMe) { console.log('Login will be remembered.'); res.cookie('user', userObj, { signed: true, httpOnly: true, path: '/' ...

Issues have arisen with the execution of JavaScript code inside a callback function

When the warnBeforeNew variable is set to false in the JavaScript code below, the file open function works as expected. However, when warnBeforeNew is true, an error occurs stating "Uncaught TypeError: Cannot read property 'root' of undefined". ...

A React component created in a class cannot effectively update its state when using a functional component to pass

I'm currently working on a React project that involves both a Class component and a Functional Component. In my Class component, I have a function that updates the name in its state. The issue arises when I try to pass this function as a property to t ...

When utilizing the Map.get() method in typescript, it may return undefined, which I am effectively managing in my code

I'm attempting to create a mapping of repeated letters using a hashmap and then find the first non-repeated character in a string. Below is the function I've developed for this task: export const firstNonRepeatedFinder = (aString: string): strin ...

To enhance the MUI v5 table row, simply apply a border when the mouse hovers

After working on creating a table with Material UI v5, I encountered an issue where I wanted to add a blue border to the table row when the mouse pointer hovered over it. I attempted several methods and did thorough research, but unfortunately, I was unab ...

Press anywhere outside the slide menu to close it using Javascript

Hey, I've looked around and can't find a solution to my issue. I have a javascript menu that currently requires you to click the X button to close it. I want to be able to simply click anywhere outside the menu to close it instead. <head> ...

What is the best way to pass an email as a Laravel parameter within a function using Angular?

I'm currently working on a feature that allows users to delete their account only if the input field matches their email address. However, I encountered an error: Error: $parse:lexerr Lexer Error when attempting to set this up. Here is my HTML code: ...

Changing dimensions of cube on stable base

I'm currently working on a project involving a dynamic cube that can be scaled in real time by adjusting its mesh. However, I'm facing a challenge in keeping the cube fixed to the floor while changing its height. Here's a snippet of the code ...

Leveraging the ng-hide property of one controller to adjust the ng-style attribute of another controller through a centralized global controller

Seeking assistance with accessing the boolean value of ng-hide from one controller in order to alter CSS properties of another controller utilizing a global controller. Here is the jsfiddle link: https://jsfiddle.net/dqmtLxnt/ HTML <div ng-controller= ...

What is the reason for placing a ReactJS component, defined as a function, within tags when using the ReactDom.render() method?

As someone who is brand new to ReactJS and JavaScript, I am struggling to grasp the syntax. The component I have created is very basic: import React from 'react' import ReactDom from 'react-dom' function Greetings() { return <h1&g ...

What is the best way to set up the login page and logged-in homepage using Node, Express, and Passport with the "/" route?

I am currently in the process of developing an application using Node.js, Express.js, and Passport.js. My goal is to create a seamless user experience on the homepage where if you are not logged in, you will see a login form (with potential for additional ...

Adjust Fabric js Canvas Size to Fill Entire Screen

Currently, I am working with version 4.3.1 of the Fabric js library and my goal is to adjust the canvas area to fit its parent div #contCanvasLogo. I have tried multiple approaches without success as the canvas continues to resize on its own. Below is the ...

JavaScript - Deleting the last element of an array

I have currently integrated a third-party API to visualize data using Highcharts. This external API provides data specific to the current month, such as March, April, May, and so on. graphArrOne contains an array with 251 elements. graphArrTwo contains ...

Not quite sure about the best way to showcase the results // using JavaScript

My code is posted below. I am trying to achieve a functionality where, upon clicking the 'Calculate Price' button, the results showing the number of cars, type of cars, and their respective prices are displayed beneath the button. Despite this be ...

Is it possible to employ a jQuery handler as the selector for the .on() method?

Can a jQuery handler $(...) be used as the selector for .on()? The code snippet below illustrates this: how can I change the circle's color to blue without having a plain text representation of my selector, but still using a handler? // This works. ...

One common issue popping up in Webpack logs is the error message "net::ERR_SSL_PROTOCOL_ERROR" caused by a call to sock

Using react on the front-end and .net core 3.1 on the back-end. Running webpack on localhost:8080 for client-side development. Configuring proxyToSpa in Startup.cs: applicationBuilder.UseSpa(spa => { spa.UseProxyTo ...

The issue of actions failing to flow from sagas to reducers in React.js

Upon user login, the success response is received but the action is not passed to the reducer. Strangely, during user registration, everything works smoothly. //saga.js import { put, takeEvery, all, call } from 'redux-saga/effects'; import {getRe ...