I am using Date.now() and Date.now in mongoose model.
I am a little bit confused about the difference between them. Could you please help me?
I know this is an old question, but the accepted answer doesn't explain the difference properly. It explains the difference in behaviour, but not how it actually works.
In your mongoose schema, your default can be either a value of the specified type or a function that returns a value of the specified type. Date.now is a built in Javascript function that returns the current unix timestamp as a number.
If you pass Date.now as the default in your mongoose schema, you are passing the function and mongoose will call that function every time a document needs a default value for that property. This results in the current time, at the time of document creation, being stored as the value for that property.
However, if you pass Date.now() instead, you are passing the value returned by Date.now() rather than the function. By doing this, your documents will get the current time, at the time of schema creation, as the default value for that property. This means that your documents will store the time of the latest deployment, which is probably not what you want.
If Date.now was a constant "replaced by Mongoose with the current datetime when creating a new record", as suggested by the accepted answer, then the following should logically work:
validUntil: {
type: Date,
default: Date.now + 3*60*60*1000 // 3 hours from now
}
But Date.now is not magically replaced by mongoose, it's a function and you can't add a number to a function. However, you can call a function inside your own function and add a number to the result, as demonstrated below:
validUntil: {
type: Date,
default: () => Date.now() + 3*60*60*1000 // 3 hours from now
}
As it wasn't clear from the accepted answer that Date.now is a function and not a mongoose constant, I wanted to clarify that. The difference between Date.now() and Date.now is that Date.now() calls the function and returns the result, while Date.now returns the function itself.
Date.now can be used in your Mongoose schema definition to set a default value for a field, whereas Date.now() is the JavaScript equivalent. For example, when setting a default value in your schema definition, you use Date.now. With this schema definition, Mongoose will populated createdDate with the current time.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
//schema
var yourSchema= new Schema({
text: {type: String},
createdAt: {type: Date, default: Date.now}
});
However, when writing JavaScript code against your schema, you have to use Date.now()
yourSchema.pre('save', function doSomething(next){
var something = this;
something.createdAt(Date.now());
next();
});
Related
I get Date from user in the string format and I currently convert into a Date in controller before creating the Schema object and saving. Is there a way to move this logic to model as it seems to me that Model is the right place for this
var RunSchema = new Schema({
created: {
type: Date,
default: Date.now
},
starttime: {
type: Date,
default: Date.now
}
});
Currently I do this
//req.body = {starttime;'2.05.2013 11:23:22'}
var run = new Run(req.body);
// util.getDate(datetime) returns false if invalid and Date() if valid
// req.body.starttime = '2.05.2013 11:23:22';
run.starttime = util.getDate(req.body.starttime);
run.save(function(err) {
if(err) {
} else {
}
});
On a sidenote, how do I assert if I want to process the param in custom function checks. Something like
req.assert('name', 'Name can\'t be empty').len(1, 1000);
While I'm not sure about the meaning of req.body.starttime, I'm pretty sure you're looking for the Schema objects pre() function which is part of the Mongoose Middleware and allows the definition of callback functions to be executed before data is saved. Probably something like this does the desired job:
var RunSchema = new Schema({
[...]
starttime: {
type: Date,
default: Date.now
}
});
RunSchema.pre('save', function(next) {
this.starttime = new Date();
next();
});
Note that the callback function for the save event is called every time before a record is created or updated. So this is for example the way for explicitly setting a "modified" timestamp.
EDIT:
Thanks to your comment, I now got a better understanding of what you want to achieve. In case you want to modify data before it gets assigned and persisted to the record, you can easily utilize the set property of the Schema:
// defining set within the schema
var RunSchema = new Schema({
[...]
starttime: {
type: Date,
default: Date.now,
set: util.getDate
}
});
Assuming that the object util is within scope (required or whatever) your current implementation fits the signature for the property set:
function set(val, schemaType)
The optional parameter schemaType allows you to inspect the properties of your schema field definition if the transform process depends on it in any way.
I've been tearing my hair out for the past 2 hours, At first I thought Moment.js is the culprit for not returning a correct time, but it was mongoose Date.now that has been doing some evil stuff.
Here's the code
const moment = require('moment');
const mongoose = require('mongoose');
const item = new mongoose.Schema({
time: { type: Date, default: Date.now },
time2: { type: Date }
});
As you can see I have two fields, one is for the default date from mongoose and the other one is just a field for storing date.
item.pre('save', function() {
console.log(moment()); // Showing a correct date and time
console.log(this.time); // Showing a correct date but false time
this.time2 = moment(); // When it is saved to the database, it will show a correct date but false time
});
The result is
moment("2017-01-09T19:42:48.896") // the first console.log. This is correct, the time is correct
2017-01-09T11:42:48.884Z // Second console.log. The date is correct but the time is FALSE
I thought If I do this everything will be solved
const item = new mongoose.Schema({
time: { type: Date, default: moment() },
time2: { type: Date, default: Date.now }
});
But you know what is the console.log for the first field which is time?
2017-01-09T11:42:48.884Z // it is this time which is WRONG TIME
My guess would be that mongoose data type which is Date has an inaccurate timezone check.
Any help would be appreciated.
You are comparing two different things. moment() gives time in local time zone and Date.now is time in UTC. The only reason mongoose has that way is because mongo db saves it that way. No fix is required here.
Just convert the fetched mongoose date back to local time zone using moment library.
I am struggling to insert a document inside another document. I've looked at all the entries like this but they aren't quite what I am looking for.
Here is the scenario:
I have a common document that has its own schema. Lets call it a related record:
(function(){
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var relatedRecordSchema = new Schema({
params: {
recordId: Schema.Types.ObjectId,
recordType: String,
recordTitle: String
},
metadata: {
dateCreated: {type: Date, default: Date.now}
}
},{ _id : false });
mongoose.model('RelatedRecord', relatedRecordSchema);
})();
I have no trouble inserting this in an ARRAY inside document that require it. I.e its configured this way:
//Embedded
relationships: {
following: [mongoose.model('RelatedRecord').schema],
followers: [mongoose.model('RelatedRecord').schema],
blocked: [mongoose.model('RelatedRecord').schema]
}
This works perfectly.
The scenario that does not work is where there is a single related record, lets say the source of a notification:
var notificationSchema = new Schema({
params: {
title: String,
imageUrl: String,
source: mongoose.model('RelatedRecord').schema
},
metadata: {
dateCreated: { type: Date, default: Date.now },
dateViewed: Date
}
});
So when I am creating the notification I try and assign the previously prepared RelatedRecord
returnObj.params.source = relatedRecord;
The record appears during a debug to be inserted (it is inside a _docs branch but far deeper than I would expect) but when the object is saved (returnObj.save()) the save routine is abandoned without error, meaning it does not enter into the callback at all.
So it looks to me that i'm confusing mongoose as the dot assignment is forcing the subdoc into the wrong location.
So the question is simple:
How do I set that subdocument?
What the question isn't:
No I don't want to populate or advice on how you would solve this problem differently. We have sensible reasons for doing things how we are doing them.
Cheers
b
As Hiren S correctly pointed out:
1) Sub-Docs = array, always. Its in the first line in the docs :|
2) By setting the type to mixed, assignment of the object worked.
I'm a dumdum.
I have many fields in my documents of type date intervals, such as this
{
publishDate:
{
start: {type: Date, required: true},
end: {type: Date, required: true}
}
}
To reduce duplication of the code and make it easier to maintain, how to create custom Mongoose type, for instance DateInterval, containing two fields:
start
end
and containing validator that makes sure both fields are filled out, and start is before end?
You can reuse schemas in mongoose.
var DateIntervalSchema = new Schema({
start: {type: Date, required: true},
end: {type: Date, required: true}
});
var SomeSchema = new Schema({
publishDate: [DateIntervalSchema],
// ... etc
});
You can also reference documents from other collections.
var SomeSchema = new Schema({
publishDate: {type: Schema.ObjectId, ref: 'DateInterval'}
});
//using populate
SomeModel.findOne({ someField: "value" })
.populate('publishDate') // <--
.exec(function (err, doc) {
if (err) ...
})
You'll want to develop a custom schema type. There are a number of plugins that do this already, one of which, for long numbers, can be found here: https://github.com/aheckmann/mongoose-long/blob/master/lib/index.js . This is a good basic example to follow.
For your purposes, then, you can create a DateInterval custom schema, casting it as type Date, and then use a validator to check start and end - http://mongoosejs.com/docs/api.html#schematype_SchemaType-validate.
Since mongoose >=4.4 you can implement your custom schema type.
Documentation is not very clear, but you can follow this example.
You have to:
define your DateInterval custom object with toBSON() / toJSON() and toObject() prototype methods
define the DateIntervalType inherited from mongoose.SchemaType for handle the mongoose integration, and casting to DateInterval.
In this way you can achieve full control on memory (Mongoose model) and mongodb (raw's bson) data representation.
I'm trying to write a mongoose schema that for all call to find() or findOne() will pass a certain value in one of its fields. I tried using the 'default' property on the field declaration, but that didn't work for me.
Here's my schema:
var schema = Schema({
created_at: Date,
type: {type: String, default: "alert"},
timestamp: Number,
order: Number,
description: String,
status: String,
});
I would like every call to find() and findOne() to pass the value "alert" in the "type" field.
Any ideas?
You could add a simple wrapper method to your model which will be responsible for finding every document with type: "alert". Something like this:
var Model = mongoose.model('Model', theSchema);
Model.alerts = function (q, callback) {
q.type = "alert";
this.find(q, callback);
}
Then you could get what you want with Model.alerts({}, callback).