I have a strange problem and cannot figure out what the problem is. The Error-message doesn't help.
I'm sending an "alarm" to the server and want to save this alarm to my "device" which already exist in the database.
The alarm object I send to the server looks like this:
{
actionTaken: "none",
dateTime: "20152111191512",
difference: 4.88,
timestamp: 1448128894781
}
The Schema for the device is as follows:
var deviceSchema = new Schema({
deviceId: {
type : String,
index : {
unique : true,
dropDups : true
}
},
alarms : [ {
timestamp : Number,
dateTime : String, //yyyymmddhhss
difference : Number,
actionTaken : String, //"send sms"
} ]
});
I load the device from the database (deviceId
is set):
Thermometer.findOne({
deviceId : deviceId
}, function(error, device){
//error handling
var now = (new Date().getTime());
var nowDateTime = (new Date()).toISOString().slice(0, 19).replace(/[-T\s:]/g, "");
var newAlarm = {
timestamp : now,
dateTime : nowDateTime, // yyyymmddhhmmss
difference : diff,
actionTaken : "none"
};
device.alarms.push(newAlarm); //EXCEPTION !
// device.save //doesn't get called
});
As you can see in the comment, I get an Exception/Error when I want to push the "newAlarm"-object to the alarms-array of my device.
The Error says:
Cast to string failed for value
[object Object]
at pathalarms
Error-Object:
kind: "string",
message: "Cast to string failed for value "[object Object]" at path "alarms"",
name: "CaseError",
path: "alarms",
stack: undefined,
value: {actionTaken: "none", dateTime: "20152111191512", difference: 4.88, timestamp: 1448128894781}
Do you have an idea?
For me it doesn't make any sense. The array and its content (object) is specified in the Schema. Why is there a string cast error with the whole object as value?
What I use:
"express": "3.2.6",
"express-session":"1.7.6",
"hjs": "*",
"mongoose": "4.0.5",
"nodemailer": "1.4.0"
EDIT: I don't want to use nested Schemas. It is also possible to do it with arrays. I do it with arrays in some other Schemas.
EDIT 2:
I added an property lastAlarm
and do
device.lastAlarm = alarm;
but after that, thermometer.lastAlarm is still undefined... but alarm is an object. So is it possible that the device object is locked some how?
Mongoose interprets the object in the Schema with key 'type' in your schema as type definition for that object.
deviceId: {
type : String,
index : {
unique : true,
dropDups : true
}
}
So for this schema mongoose interprets deviceId as a String instead of Object and does not care about all other keys inside deviceId.
SOLUTION:
Add this option object to schema declaration { typeKey: '$type' }
var deviceSchema = new Schema(
{
deviceId: {
type : String,
index : {
unique : true,
dropDups : true
}
},
alarms : [ {
timestamp : Number,
dateTime : String, //yyyymmddhhss
difference : Number,
actionTaken : String, //"send sms"
} ]
},
{ typeKey: '$type' }
);
By adding this we are asking mongoose to use $type
for interpreting the type of a key instead of the default keyword type
Mongoose Docs reference: https://mongoosejs.com/docs/guide.html#typeKey
I would declare alarm as its own schema and set the alarms property as an array of alarm aka subdocuments. This will allow you to add validation to the alarm schema, etc. NOTE: Subdocuments don't get saved until the parent is saved.
var alarmSchema = new Schema({
timestamp : Number,
dateTime : String, //yyyymmddhhss
difference : Number,
actionTaken : String, //"send sms"
});
var deviceSchema = new Schema({
deviceId: {
type : String,
index : {
unique : true,
dropDups : true
}
},
alarms : [alarmSchema]
});
Maybe it is too late, but here mongoose is assuming that deviceId is not an object and it is of type String
deviceId: {
type : String,
index : {
unique : true,
dropDups : true
}
},
SIMPLE SOLUTION:
deviceId: {
type: {
type: String
},
index: {
unique: true,
dropDups: true
}
},
Wow, 5 years late but I recently faced this problem. All you need to do is specify the type in an object for nested routes. So your code would change to:
var deviceSchema = new Schema({
deviceId: {
type : { type: String },
index : {
unique : true,
dropDups : true
}
},
alarms : [ {
timestamp : {type: Number},
dateTime : { type: String }, //yyyymmddhhss
difference : {type: Number},
actionTaken : { type: String }, //"send sms"
} ]
});
So for nested objects, you'd need to use field: {type: String}
and not field: String
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With