Time format in mongoose scheema Object - node.js

I have schema object like below
schedule: [{
time: {
type: Date,
required: true
}
}]
and when I try to post data in postman as
"schedule":[
{
"time":"18:00:00"
}]
I'm getting following error
validation failed: schedule.1.time: Cast to Date failed for value "12:00:00"
if I define type as String, everything is working fine.
I think I'm wrong at defining the type to accept the time. Can any one please help me to better way to define the object type

I have a simple question for you, Do you want to store just time(no date component eg. 18:00:00) or as a timestamp(date and time eg. 2019-06-11T06:24:46.642Z)?
If it's just time, then unfortunately you can't store it in date typed field because it accepts either date or a timestamp whereas string type can accept any arbitrary string.
I would either suggest storing 18:00:00 as string then process in however way you want after retrieval or storing a timestamp with field typed as date and use it along with its corresponding date.
Just to explain about the error, it occurs because 18:00:00 is no valid way to represent a date since the field is date typed.

As you have noticed, the type of field you have defined does not match the data you want to store in it. If you define it as type: Date, it will only accept valid dates and "18:00:00" is not.
From what I understand you want to do, I think the best option may be to store a valid date object even if you are only going to show or edit in your code the time on the client side.
Another possibility could be to declare three number fields at your model: hours, minutes and seconds.
EDIT:
To store just the time as you are asking for, the model could look like:
schedule: [{
hours: {
type: Number, required: true, min: 0, max: 23
},
minutes: {
type: Number, required: true, min: 0, max: 59
},
seconds: {
type: Number, required: true, min: 0, max: 59
}
}]
I don't know how are you going to treat this data but you could get a string like the one you were trying to store with a function like this:
function timeToString(h, m, s) {
if (h < 10) h = '0' + h;
if (m < 10) h = '0' + h;
if (s < 10) h = '0' + h;
return h + ':' + m + ':' + s;
}

Look the message it has telling
time: Cast to Date failed for value
Time and Date are different things
If you need to use the time following works as well
{
"time":"2019-06-12T13:34:00.000"
}

It's possible to create a custom type and store time. But I suggest you store the time as a string. In this case, a string is easy to parse, maintain and retrieve.
Add custom validation like this.
time: {
type: String,
validate: {
isAsync: true,
validator: function(v, cb) {
setTimeout(function() {
var timeRegex = /^(?:2[0-3]|[01][0-9]):[0-5][0-9]:[0-5][0-9]$/;
var msg = v + ' is not a valid time format!';
cb(timeRegex.test(v), msg);
}, 5);
},
message: 'Default error message'
},
required: [true, 'Time is required']
}

Related

Date Format in mongoose, mongodb and node application

First time question and newbie coder so treat me like I'm 5 years old.
Okay so as I'm learning, I'm horrible at trying to understand how to use documentation to fix my problems. I'm setting up a node application with mongodb as the backend. The starting point is it is something that will pull via api baseball game results into a database (date, teams, scores). The problem I've ran into is I want to take in dates. When I do it comes back with the generic 1970's date and I can't seem to get it to just keep the formatted date. The source of the data and the date will be given programmatically and so it won't be prone to human error so I don't need date validation. I just need it to recognize the date and keep it's format so I can find or filter on it. The data will only have the year/month/date and not the time.
I'm setting this up in a mongoose file to load into my mongodb DB.
I've looked at https://mongoosejs.com/docs/api.html#mongoose_Mongoose-Date information, but I'm either missing the point or not seeing what's in front of me. Any hints on how to accept date information?
const GameDayStats = mongoose.model('GameDayStats', {
Date: {
type: Date
},
Home: {
type: String
},
HomeScore: {
type: Number
},
Visitor: {
type: String
},
VisitorScore: {
type: Number
},
Final: {
type: Boolean
}
})
const game = new GameDayStats({
Date: 2021-08-04,
Home: 'Cardinals',
HomeScore: 8,
Visitor: 'Pirates',
VisitorScore: 2,
Final: true
})
game.save().then(() => {
console.log(game)
}).catch((error) => {
console.log('Game Stat Error!', error)
})
What the output looks like
{
_id: 602e774fbee0692662ea16fa,
Date: 1970-01-01T00:00:02.009Z, <----I want this in normal date form
Home: 'Cardinals',
HomeScore: 8,
Visitor: 'Pirates',
VisitorScore: 2,
Final: true,
__v: 0
}

Sequelize/tedious parsing datetime wrong to where clause

I am getting no results in sql query because the filter in where clause was changed by sequelize/tedious before query is executed.
const query = `SELECT field FROM Table WITH(NOLOCK) WHERE CreationDate BETWEEN '${startDate}' AND '${endDate}'`
return sequelize.rawQuery(query)
.then((resultado) => {
return resultado;
})
.catch((error) => {
console.log('error')
});
This is the query generated by sequelize/tedious
SELECT [Field]
FROM [Table] AS [Table] WHERE
([Table].[CreationDate] > N'2018-02-01 16:36:00.000 -02:00' AND [Table].[CreationDate] < N'2018-02-01 16:46:00.000 -02:00')
Can you help me how to solve this?
CreationDate is stored as YYYY-MM-DD HH:MM:SS
I have also been banging my head on this for the last week.
It should have been solved here and has been discussed here and here. But I don't think it really has been solved.
I know this isn't the correct way, but you could change the schema from this:
CreationDate: {
type: DataTypes.DATE,
allowNull: true
},
to
CreationDate: {
type: DataTypes.INTEGER,
allowNull: true
},
and then convert your startDate and endDate to integers like:
Date.parse(startDate) / (1000 * 60 * 60 * 24)
I really hope someone can help, because the Tedious documentation is kind of hard to understand.
This solved my problem for now, until I fix it. Only ever had this problem with mssql.

Mongoose create new data with incremented index-like field

What I want to do:
Whenever I add a new item to the collection (in my case a game), it will have a incremented "index"-like value (in my case I'm naming it index too).
My games collection should looks like:
[
{ "index":0, ... data }
{ "index":1, ... data }
{ "index":2, ... data }
]
The term is so hard to search. I always end up with:
$inc for update. Not this, I want to have incremented number on create.
Schema.index does look like what I want, but somehow it doesn't work at all:
const gameModel = new Schema({
index: {
type: Number,
default: 0
},
players: [{
name: String,
score: Number
}]
}, {
timestamps: {
createdAt: 'date'
}
});
gameModel.index({
index: 1
});
With this I always get index: 0. If I turn off default no index is created.
What do I do now? (I would prefer to keep the _id intact)
You can use a npm package named mongoose-auto-increment which provides this functionality. It is also very easy and well documented

String + autoincrement number on mongoose

I want to create a String + number every time a value is inserted on database (the number must be autoincrement).
Is it possible to do in Schema? Or do I need to do that before the value's inserted on database?
'question' -> String followed by an autoincrement number
var random = [{
question: 'question1'
},{
question: 'question2'
},{
question: 'question3'
},{
question: 'question4'
}];
const RandomSchema = new Schema({
question: {
type: String,
unique: true
}
})
Autoincrement fields in Mongodb, don't work exactly the same way that they do in an RDBMS. There is a lot more overhead involved. Never the less, creating an auto field is a solved problem. There is also a third party mongoose-autoincrement package that make it a lot easier.
Extending, from that. Your problem is a solved problem too. Because
the string part will always be the same
Simply use string concatenation to prepend 'question' to the auto increment field at display time.
Here is what I implemented with one of the approaches #e4c5 pointed out, without the use of a third-party package.
Define add.js as below:
db.counters.insert(
{
_id: "itemid",
seq: 0
}
)
function getNextSequence(id) {
var ret = db.counters.findAndModify(
{
query: { _id: id },
update: { $inc: { seq: 1 } },
new: true
}
);
return ret.seq;
}
db.randoms.insert(
{
question: "question"+getNextSequence("itemid"),
}
)
db.randoms.insert(
{
question: "question"+getNextSequence("itemid"),
}
)
After starting a mongod instance, do mongo < add.js.

Sequelize is returning integer as string

I using nodejs v4 with sequelize, and I have a model like this:
var Device = sequelize.define('Device', {
id: {
type: DataTypes.BIGINT,
primaryKey: true,
autoIncrement: true
},
tenantId: {
type: DataTypes.BIGINT,
allowNull: false
},
token: {
type: DataTypes.STRING,
allowNull: false
}
}, {
tableName: 'devices'
});
When I select a device by id the type of id is a string, exemple:
Device.findById(9).then( function(result) {
console.log(result.toJSON().id + 10);
});
The output will be 910, rather than 19, so I look at json and a saw this:
{
id: "9"
tenantId: "123"
token: "adsadsdsa"
}
The id in found device is a string, but I defined it as a number...
Doesn't it should be { "id": 9 } ?
How can I select a device with the types that I defined previously?
BIGINT maximum value is 2^63-1, javascript can safely represent up to 2^53. To be on the safe side libraries return those numbers as strings.
If you want to have numbers instead of strings, you can use this library https://github.com/mirek/node-pg-safe-numbers which deals with this issue.
I found a fix to this problem on sequelize repo.
https://github.com/sequelize/sequelize/issues/4523
The pg module used for sequelize returns bigint as string because bigints are not guaranteed to fit into js numbers. So I change my model to use integer (DataTypes.INTEGER)
IMO, a smoother solution is to force parsing of int to int, instead of strings. Checkout this issue and comments.
Trying to put this line before your logic code worked for me, this forces parsing of int8 to int, instead of strings:
require("pg").defaults.parseInt8 = true;
...
try {
const list = await Posts.findAll();
console.log(JSON.stringify(list));
} catch (e) {
console.log(e.message);
}
By default, sequelize try format your results. You can set raw :true for get raw data

Resources