validation Cast to Number failed - javascript

Im getting validation error at path badgeid, why am i getting this when my getting it when badgeid is a number, and what im saving is a number?`
Checks that i already checked:
achievement value is 5,
achievement type is Number
error:
(node:8260) UnhandledPromiseRejectionWarning: ValidationError: achievement_users validation failed: badgeid: Cast to Number failed for value "{ badgeid: 0,
progress: 0,
_id: 5c94c04a758c8a204440499e }" at path "badgeid"
save code:
var achievement = new achivementUsers();
achievement.badgeid = achievement;
return achievement.save().then(function (response) {
schema:
{
badgeid: {type: Number, default: 0},
progress: {type: Number, default: 0},
completed: {type: Boolean, default: false},
userid: {type: String, default: 'No name'},
}

You are overriding the variable achievement. You are setting achievement with the new model so you need to use another name instead:
//somewhere in the code `achievement` is 5
var achievementUser = new achivementUsers();
achievementUser.badgeid = achievement;
return achievementUser.save().then(function (response) {});
Or you can initialize the value when you create the model object. But it is still a good practice to use different variable names for different context.
//somewhere in the code `achievement` is 5
var achievement = new achivementUsers({
badgeid: achievement
});
return achievement.save().then(function (response) {});

Related

nodejs objects property can only be changed to int and not string

i just got this wierd issue in which the code below returns the refno for all Object in the array as expected But
let records = await Expense.find({}).exec(); // records is an array of objects [{},{}]
for (let obj of records) { // the obj has a refno property which i want to change
obj.refno = 0 // this works as expected by changing refno property to 0
}
console.log(records)
this code of code below of chaning the properties value to string Does not work
for (let obj of records) {
obj.refno = "QM"+obj.refno
}
console.log(records) // IN this the refno. doesnt change
my requirment is to change the refno to a string
//the object
{
_id: 5efed2c813b03d331e4dc052,
refno: 102,
project: 'EV Battery Pack',
invoiceno: 'dia',
description: 'black frame',
date: '2020-07-03',
}
so chaning the property to other number works but not to string , i cant get how this happens or am i missing something ?, anyways i got around this by declaring another property and storing the string in it but I dont know why the int cant be changed to string inside object
can some one explain why this happens
thanks for help
Edit : schema of expense
var schema = new Schema({
refno: { type: Number, require: true },
project: { type: String, require: true },
projectid: { type: Number, require: true },
invoiceno: { type: String, require: true },
description: { type: String, require: true },
date: { type: String, require: true },
INR: { type: Number, require: true },
USD: { type: Number, require: true },
remarks: { type: String, require: true },
});
The result of your .find().exec() call are mongoose documents which do not allow to modify their values if the resulting datatype is not compliant with the schema-constraints.
However, you can use .lean() (see https://mongoosejs.com/docs/api.html#query_Query-lean) on the mongoose document which will convert it to a plain js-object which you then can modify arbitrarily:
let records = await Expense.find({}).exec().lean();

Mongoose use float as key

I'm trying to use floats as keys in a mongodb database since I have to store the respective amount of each money value (e.g. 0.01: 10). But when I try saving the data via mongoose (node server using express) it only saves the data with normal (String) keys in the db.
This is my schema:
var ProtokollSchema = new Schema({
"date": String,
"0.01": {type: Number, default: 0},
"0.02": {type: Number, default: 0},
"0.05": {type: Number, default: 0},
"0.10": {type: Number, default: 0},
"0.20": {type: Number, default: 0},
"0.50": {type: Number, default: 0},
"1.00": {type: Number, default: 0},
"2.00": {type: Number, default: 0},
...
});
This is the express function setting the data:
.post(function(req, res) {
var protokoll = new ProtokollSchema();
protokoll["date"] = req.body["date"];
protokoll["0.01"] = req.body.data["0.01"];
protokoll["0.02"] = req.body.data["0.02"];
protokoll["0.05"] = req.body.data["0.05"];
protokoll["0.10"] = req.body.data["0.10"];
protokoll["0.20"] = req.body.data["0.20"];
protokoll["0.50"] = req.body.data["0.50"];
protokoll["1.00"] = req.body.data["1.00"];
protokoll["2.00"] = req.body.data["2.00"];
...
protokoll.save(function(err) {
if (err) res.json(err);
res.json({ message: "Comment successfully added!"});
});
})
Is there a solution or is it just not possible to do?
All keys in a schema must be a string whatever the key string looks like a normal string, a float or others.
Make sure that req.body.data be really with values like {"0.01": xxx, "0.02": xxx, ...};
You should use Model to create a document instead of Schema
//wrong way
var protokoll = new ProtokollSchema();
//Right way - Use the schema to generate a model and use model to new a docuemnt.
var Protokoll = mongoose.model('Protokoll', ProtokollSchema);
var protokoll = new Protokoll({"0.01": xxx, "0.02": xxx, ...});
The actual problem was that MongoDB simply doesn't support dots in its keys (see this question) Initially I thought the problem was the Schema of mongoose but obviously it wasn't.

update return matched

How can i make this update work?
current error:
MongoError: cannot use the part (cartheft of crimes.0.cartheft.chance) to traverse the element
i also tried to put $, but then i get:
(node:10360) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): MongoError: Too many positional (i.e. '$') elements found in path 'crimes.$.cartheft.$.chance'
code:
cartheft_crime.update({
userid: req.user._id,
"crimes.location": 1,
"crimes.cartheft.theftid" : 1,
}, {$inc: {"crimes.$.cartheft.chance": 1000}}).then(function (response) {
res.json(response);
});
model:
userid : String,
crimes: [{
location: {type: Number, default: 1},
lastcartheft: {
time: {type: Number, default: 1},
type: {type: Number, default: 1},
},
cartheft: [
{
id: {type: Number, default: 1},
theftid: {type: Number, default: 1},
chance: {type: Number, default: 200},
success: {type: Number, default: 0},
failure: {type: Number, default: 0},
},
],
}],
ip: String
Looking at the documentation here is how the positional operator $ handle arrays :
Nested Arrays
The positional $ operator cannot be used for queries which traverse
more than one array, such as queries that traverse arrays nested
within other arrays, because the replacement for the $ placeholder is
a single value
So you cannot perform the increment that way. You should retrieve the data, modify it programmatically and then save the change.
For example :
// Get the user data
cartheft_crime.findOne({
userid: req.user._id,
})
.then((ret) => {
// We have no user behind req.user._id
if (!ret) throw new Error('Cannot find the user');
// Modify the data
const user_obj = ret;
// Get the right crime to modify
const right_crime = user_obj.crimes.find(x => x.location === 1);
// Cannot find it
if (!right_crime) throw new Error('Cannot find the appropriate crime');
// Get the right cartheft to modify
const right_cartheft = right_crime.cartheft.find(x => x.theftid === 1);
// Cannot find it
if (!right_cartheft) throw new Error('Cannot find the appropriate cartheft');
// Finally modify the data
right_cartheft.chance += 1;
// Save the data
return user_obj.save();
})
.then(() => {
// It's done !
})
.catch((err) => {
// Send the error ...
});

Mongoose typeError with custom Schema

I'm trying to use discountSchema as a type. But I'm getting this error:
throw new TypeError('Undefined type at `' + path +
^
TypeError: Undefined type at `discount`
but if I transform to type array:
discount: {
type: [discountSchema],
default:{}
}
it works.
How can I use complex type in mongoose as this?
Am I using this model in a wrong way? How can I model this object like this?
var discountSchema = new Schema({
type: {type: String,default:'' },
quantity: {type: Number,default:0 },
value: {type: Number,default:0 }
});
var objectEncomendaPropertiesSchema = {
recheios:{
type:[String],
default: [],
select: true
},
availableEncomenda: {
type: Boolean,
default:false
},
discount: {
type: discountSchema,
default:{}
}
};
You cant't set embedded documents stored as single property in mongoose, they are always stored in arrays.
The closest thing to this behaviour is setting your property to an ObjectId with a ref and using the populate method to fetch it.
Take a look here to see how this approach works.
Check out embedded documents docs.
There is an open issue on GitHub requesting the behaviour you want.
are you trying to create two Schemas then wire them up?
var discountSchema = new Schema({
type: {type: String,default:'' },
quantity: {type: Number,default:0 },
value: {type: Number,default:0 }
});
mongoose.model('Discount', discountSchema);
var objectEncomendaPropertiesSchema = new Schema({
recheios:{
type: String,
default: '',
select: true
},
availableEncomenda: {
type: Boolean,
default:false
},
discount: {
type: Schema.Types.ObjectId,
ref: 'Discount'
}
})
mongoose.model('objectEncomendaProperties', objectEncomendaPropertiesSchema);
I reference the discount in the second schema to reference to the first schema by the ObjectId
It will fetch the properties in the Discount model as a discount property in the second Schema.

Updating a child object property of a parent object which needs to be populated in mongoose

I'm new to Mongoose and I'm having difficulty getting my head around accessing properties deeper in the model and updating properties on the following model structures.
Game Schema
var gameSchema = new Schema({
opponents: [{
type: Schema.Types.ObjectId,
ref: 'teams'
}],
startTime: { type: Date, default: Date.now },
endTime: Date,
pauses: [{
start: Date,
end: Date
}],
winner: {
type: Schema.Types.ObjectId,
ref: 'teams'
},
status: {type: String, default: "created"},
score: [{
"opponent1": {type: Number, default: 0},
"opponent2": {type: Number, default: 0}
}],
}, { versionKey: false });
Team Schema
var teamSchema = new Schema({
name:String,
badge:String,
goals:[{type: Date, default: Date.now}],
totalWins:Number
}, { versionKey: false });
My problem is I'm trying to add a goal to a team from a specific game.
So my end point:
POST: /api/game/GAME_ID/goal
DATA: {_id: TEAMID}
I thought the following would work:
Games.findById(GAME_ID)
.populate('opponents')
.find({'opponent._id': TEAM_ID})
.exec(function(err, team) {
// Team from game with matching ID returned
// Now push goal time into array
team.goal.push(Date.now());
});
The above does not appear to return a team. if I remove the second find the game is returned and then I have to do something horrible like this:
Games.findById(GAME_ID)
.populate('opponents')
.exec(function(err, game) {
if(game.opponents[0]._id.toString() === req.body._id) {
game.opponents[0].goals.push(Date.now());
} else if (game.opponents[1]._id.toString() === req.body._id) {
game.opponents[1].goals.push(Date.now());
} else {
// Throw error no matching team with id
}
});
game.save(function(err, game) {
//Game saved
});
this last example appears to work but when I try to add further goals pushing into the goals array it overwrites the old goal time.
So to recap.
How do I query the Games model to retrieve a child by id which has
yet to be populated?
How do I set push the goal time stamp into the goals array without
overwriting the previous one?
Is it possible to do these a bit more gracefully than the current example given above.
Games.findById(GAME_ID)
.populate(
path: 'opponents',
match: { _id: TEAM_ID}
)
.exec(function(err, team) {
// Team from game with matching ID returned
});

Categories

Resources