Amir
Amir

Reputation: 19

TypeError: undefined is not a function - node.js

I've seen this asked before but haven't found an answer. My function is clearly defined, I even put a breakpoint right before I call it and I checked it's 'typeof'.

Basically, I'm importing a utilites.js file to validate a result after find, and that validation function is called by various functions.  For some it works, for others it throws an error.  Can someone explain to me what's going on?

//Here is the file with the functions that use it: (below I'll add the utilities file)

    const mongoose = require('mongoose');
    const moment = require('moment');
    const utilities = require('./utilities');
    const models = require('../models/schemas');
    const hash = require('object-hash');
    const { Beverage, Purchase, Machine } = models;
    const { ValidatedAfterFind, ValidatedAfterUpdate } = utilities;
    const blueBirdPromise = require('bluebird');

    mongoose.Promise = require('bluebird');

    //THE VALIDATION FUNCTION WORKS HERE
    const FetchBeveragePrice = (req, res) => {
        const { beverageid } = req.params;
        let beverage = '';
        return Beverage.find({ _id: beverageid }).select('Price').exec()
            .then(returnedBeverage => {
                beverage = returnedBeverage[0]._doc;
                if(ValidatedAfterFind(returnedBeverage, beverageid)) {
                    res.send({Price:beverage.Price})
                }
                else {
                    res.sendStatus(500)
                }
            })
    }


    const AddCoins = (req, res) => {

        const { machineId, coinType } = req.body;
        if (wrongCoinType(coinType)) {
            return res.status(400).send("Wrong Coin Type")
        }
        Machine.updateOne({ _id: machineId }, { $inc: { fundsForCurrentPurchase: coinType, totalFunds: coinType } }).exec()
            .then(results => {
                if(ValidatedAfterUpdate(results, 1)){
                    res.sendStatus(200);
                }
                else {
                    res.sendStatus(500);
                }
            })

    }
    //THE VALIDATION FUNCTION DOESN'T WORK HERE
    const GetBeverage = (req, res) => {
        const { machineid, beverageid } = req.params;

        return blueBirdPromise.join(Beverage.findById({ _id: beverageid }).exec(), Machine.find({ _id: machineid }).exec(),
            (beverage, machine) => {
                if (ValidatedAfterFind(beverage, beverageid) && ValidatedAfterFind(machine, machineid)) {
                    choosePurchaseProcessByConditions (machine, beverage, res)
                }
                else {
                    res.sendStatus(500)
                }

            })
    }

    function choosePurchaseProcessByConditions (machine, beverage, res) {
        if (machine.beveragesInMachine[beverageid.toString()] > 0) {
            if (machine.fundsForCurrentPurchase >= beverage.Price || machine.currentlyApprovedCreditCard) {
                chooseStepsBeforePurchaseByBeverageType(machine, beverage, res);
            }
            else {
                res.send(`Missing ${beverage.Price - machine.fundsForCurrentPurchase} shekels`);
            }
        }
        else {
            return res.send('Out of Stock');
        }
    }

    function chooseStepsBeforePurchaseByBeverageType(machine, beverage, res) {
        if (beverage.hot) {
            if (machine.sugarUpdated) {
                addPurchaseAndUpdateMachine(res, machine, beverage)
            }
            else {
                return res.send("Choose Amount of Sugar")
            }
        }
        else {
            addPurchaseAndUpdateMachine(res, machine, beverage)
        }
    }

    function addPurchaseAndUpdateMachine(res, machine, beverage) {
        const newPurchase = new Purchase({ machineID: machine._id, creditCard: machine.currentlyApprovedCreditCard, price, creationDate: moment() });
        const change = machine.fundsForCurrentPurchase - beverage.Price;
        const updateBeveragesInMachine = `beveragesInMachine.${beverage._id.toString()}`;

        const updateFieldsForMachine = {
            $inc: {
                totalFunds: -(machine.totalFunds - beverage.Price),
                updateBeveragesInMachine: -1
            },
            fundsForCurrentPurchase: 0,
            currentBeverage: '',
            currentlyApprovedCreditCard: false,
            sugarUpdated: false
        }
        return blueBirdPromise.join(newPurchase.save(), Machine.updateOne({ _id: machineid }, updateFieldsForMachine),
            (purchaseResult, machineResult) => {
                return blueBirdPromise.join(utilities.ValidationPromiseOnUpdate(purchaseResult, 1), utilities.ValidationPromiseOnUpdate(machineResult, 1),
                    () => res.json({ change }))
                    .catch(() => res.sendStatus(500))
            })
    }


    module.exports = {
      FetchBeveragePrice,
      AddCoins,
      GetBeverage
    }


Here is the file with the validation functions:



const ValidatedAfterFind = ([result], searchedId) => result._doc._id.toString() === searchedId.toString();

const ValidatedAfterUpdate = (results, expectedModifications) => results.nModified === expectedModifications;


module.exports = {
    ValidatedAfterFind,
    ValidatedAfterUpdate
}

It's been driving me absolutely crazy, can't find the answer!

I thought it might have something to do with circular reference before but there isn't anything like that.

Any help would be much appreciated.

Thanks in advance.

Stack trace: Unhandled rejection TypeError: undefined is not a function at ValidatedAfterFind (c:\Users\Amir\Desktop\vending_machines\dal\utilities.js:16:28) at Beverage.findById.then.beverage (c:\Users\Amir\Desktop\vending_machines\dal\data.js:63:16) at tryCatcher (c:\Users\Amir\Desktop\vending_machines\node_modules\bluebird\js\release\util.js:16:23) at Promise.module.exports.Promise._settlePromiseFromHandler (c:\Users\Amir\Desktop\vending_machines\node_modules\bluebird\js\release\promise.js:512:31) at Promise.module.exports.Promise._settlePromise (c:\Users\Amir\Desktop\vending_machines\node_modules\bluebird\js\release\promise.js:569:18) at Promise.module.exports.Promise._settlePromise0 (c:\Users\Amir\Desktop\vending_machines\node_modules\bluebird\js\release\promise.js:614:10) at Promise.module.exports.Promise._settlePromises (c:\Users\Amir\Desktop\vending_machines\node_modules\bluebird\js\release\promise.js:693:18) at Async._drainQueue (c:\Users\Amir\Desktop\vending_machines\node_modules\bluebird\js\release\async.js:133:16) at Async._drainQueues (c:\Users\Amir\Desktop\vending_machines\node_modules\bluebird\js\release\async.js:143:10) at Immediate.e.Async.drainQueues (c:\Users\Amir\Desktop\vending_machines\node_modules\bluebird\js\release\async.js:17:14) at runCallback (timers.js:672:20) at tryOnImmediate (timers.js:645:5) at processImmediate [as _immediateCallback] (timers.js:617:5)

Upvotes: 1

Views: 1486

Answers (1)

Orelsanpls
Orelsanpls

Reputation: 23565

You can get this error when you are trying to destructure an object as it was an array.

My bet is that your error is here :

  if (ValidatedAfterFind(beverage, beverageid) && 
      ValidatedAfterFind(machine, machineid)) {

You should check beverage and machine there


const destructureMe = [
 'a',
 'b',
];

const destructureMeToo = {};

function func([ result ]) {
  console.log(result);
}

func(destructureMe);

func(destructureMeToo);

Upvotes: 1

Related Questions