1

I'm fairly new to Nodejs and MongoDB.

So I've built a schema in Nodejs looking like this (shown below) - Data Schema

// create Data Schema
const dataSchema = new mongoose.Schema({
    allItems: {
        // store all expenses here
        exp: [{
            description: { type: String, require: true, min: 2, max: 50 },
            value: { type: Number, require: true },
            percentage: { type: Number, require: true }
        }],
        // store all incomes here
        inc: [{
            description: { type: String, require: true, min: 2, max: 50 },
            value: { type: Number, require: true }
        }]
    },
    // store total incomes & expenses
    totals: {
        // sum of total expenses, init = 0
        exp: { type: Number, require: true, default: 0},
        // sum of total incomes, init = 0
        inc: { type: Number, require: true, default: 0}
    },
    // store total budgets, init = 0
    budget: { type: Number, require: true, default: 0 },
    // store percentage of total budget
    // init -1 = something is not in existance yet
    percentage: { type: Number, require: true, default: -1 } 
})

and have a post router to save new data to db (as shown below)

router.post('/', async (req, res) => {

    // hold exp & inc array length
    expLength = req.body.allItems.exp.length
    incLength = req.body.allItems.inc.length

    // do something to hold allItems exp & inc data first
    // do some code here?

    // create new data
    const data = new Data({
        allItems: {
            exp: [
                {
                    description: req.body.allItems.exp,
                    value: req.body.allItems.exp,
                    percentage: req.body.allItems.exp
                }
            ],
            inc: [
                {
                    description: req.body.allItems.inc,
                    value: req.body.allItems.inc
                }
            ]
        },
        totals: {
            exp: req.body.totals.exp,
            inc: req.body.totals.inc
        },
        budget: req.body.budget,
        percentage: req.body.percentage
    })

    try {
        const saveData = await data.save()
        res.json(saveData)
    } catch(err) {
        res.json({
            message: err
        })
    }
})

So I'm using Postman to help me learn about nodejs and mongodb.

In postman, I have this data (as shown below) ready to be executed. Where, I've 2 objects in array exp under allItems.

{
    "allItems": {
        "exp": [
            // first object
            {
                "description": "Rent",
                "value": 500,
                "percentage": 50
            },
            // second object
            {
                "description": "Loan",
                "value": 250,
                "percentage": 25
            }
        ],
        "inc": [
            {
                "description": "Web",
                "value": 1000
            }
        ]
    },
    "totals": {
        "exp": 750,
        "inc": 1000
    },
    "budget": 250,
    "percentage": 75
}

But unfortunately it only able to save 1 object, which is the first one since I set the array to be '0' in post router (as shown below).

{
    "totals": {
        "exp": 750,
        "inc": 1000
    },
    "budget": 250,
    "percentage": 75,
    "_id": "5e6139b3111a7b593ce296cd",
    "allItems": {
        "exp": [
            // only save the first object
            {
                "_id": "5e6139b3111a7b593ce296ce",
                "description": "Rent",
                "value": 500,
                "percentage": 50
            }
        ],
        "inc": [
            {
                "_id": "5e6139b3111a7b593ce296cf",
                "description": "Web",
                "value": 1000
            }
        ]
    },
    "__v": 0
}

I think I should do a for loop or something to store the array of inc & exp data first. But I just don't know how.

I've been searching it through google. But got no luck yet. Anyway, any help would be appreciated. Thank you.

Btw, it gave me this error (as shown below) -

"_message": "Data validation failed",
"message": "Data validation failed: allItems.exp.0.description: Cast to String failed for value \"[\n  { description: 'Rent', value: 500, percentage: 50 },\n  { description: 'Loan', value: 250, percentage: 25 }\n]\" at path \"description\", allItems.exp.0.value: Cast to Number failed for value \"[\n  { description: 'Rent', value: 500, percentage: 50 },\n  { description: 'Loan', value: 250, percentage: 25 }\n]\" at path \"value\", allItems.exp.0.percentage: Cast to Number failed for value \"[\n  { description: 'Rent', value: 500, percentage: 50 },\n  { description: 'Loan', value: 250, percentage: 25 }\n]\" at path \"percentage\", allItems.inc.0.description: Cast to String failed for value \"[ { description: 'Web', value: 1000 } ]\" at path \"description\", allItems.inc.0.value: Cast to Number failed for value \"[ { description: 'Web', value: 1000 } ]\" at path \"value\"",
"name": "ValidationError"

1 Answer 1

1

You can put a forEach loop on req.body.allItems.exp and prepare the expArr array to be saved in exp:

var expArr = [];
req.body.allItems.exp.forEach(function(eachObj){
   var obj = {
      "description": eachObj.description,
      "value": eachObj.value,
      "percentage": eachObj.percentage
   }
   expArr.push(obj);
});

Although, by looking at your code, seems like there is no need for any loop, you can just save the exp data directly like this:

router.post('/', async (req, res) => {

// hold exp & inc array length
expLength = req.body.allItems.exp.length
incLength = req.body.allItems.inc.length

// do something to hold allItems exp & inc data first
// do some code here?

// create new data
const data = new Data({
    allItems: {
        exp: req.body.allItems.exp,
        inc: req.body.allItems.inc
    },
    totals: {
        exp: req.body.totals.exp,
        inc: req.body.totals.inc
    },
    budget: req.body.budget,
    percentage: req.body.percentage
})

try {
    const saveData = await data.save()
    res.json(saveData)
} catch(err) {
    res.json({
        message: err
    })
 }
})
Sign up to request clarification or add additional context in comments.

5 Comments

It gave errors of message: Data validation failed. I've updated my question above. Please have a look at it. How can I ignore the validation?
@lala Kindly read my answer carefully. I am assigning "req.body.allItems.exp" directly to "exp" in "allItems". You are assigning "req.body.allItems.exp" to "description", "value" and "percentage". Please replace your "const data" part code with my "const data" part. It will work.
Oh sorry! My bad. Anyway, is there any particular reasons why I don't have to specify the key&value pairs of data inside exp & inc. I don't know it can work like that. Not until you showed it to me.
It depends on how the values are in "req.body", if it is in the same format as schema, you don't need to process them again before adding it to DB.
Oh nice to know! Anyway, thanks for the help! Appreciated it!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.