So, I've got this schema:
var imageSchema = new Schema( {
caption: {type: String, required: true},
url: {type: String, required: true}
});
var EventSchema = new Schema({
name: {type: String, required: true},
date: {type: Date, required: true},
time: {type: String, required: true},
location: {type: String, required: true},
description: { type: String, required: false },
image: {type: String, required: false},
images: [imageSchema]
});
Requests are handled via locomotive.js, and the controller action for creating new records looks like this:
EventController.create = function() {
if(preScreen.screen.bind(this)("event", "create")) {
this.elements = modelHelper.loadValues.bind(this)();
this.saveMessage = "Save";
this.strings = strings;
if(this.req.method && this.req.method == "POST")
{
this._createEvent();
} else {
this.render();
}
} else {
this.redirect(this.urlFor({controller: "dashboard", action: "error"}));
}
};
This is a fairly standard action controller; mostly invoking an input view or or handling the _create when the received with a POST header.
the _createEvent function looks like this:
EventController._createEvent = function() {
if(!(this.elements)) this.elements = require('../templates/Event/elements')();
if(!(this.event)) this.event = new Event();
modelHelper.populate.bind(this)(this.elements, "event", function() {
modelHelper.save.bind(this)("event", this._confirm.bind(this), "create");
}.bind(this));
};
For my models I encapsulate all of the inputs in a template pattern. Rather than spend a lot of time on the framework around this (which I am working on releasing open source once I have finished doing small tweaks too) I will say that effectively the template contains one element for each path in the schema and provides some client-side details (error messages, labels etc.) these template objects are used by a modelHelper object which is fairly agnostic. Effectively what modelHelper.populate does is inspect the "type" property of each object within elements, and calls a handler for the appropriate input type.
the handler for date types is:
case "date" :
this[record][field.name] = strings.exists(this.param(field)) ?
strings.trim(this.param(field.name)) : null;
break;
although I've also tried strings.trim(Date.parse(this.param(field.name)) to get the UTC Timestamp from the user string.
I've been able to validate that the user entered date string does return a valid UTC stamp by using console.log within the date parser.
When the modelHelper.save() call is made it runs through these template objects, creates an associate array with the values picked up from the parsers and passes it to Record.save().
Most of this has been thoroughly tested and is being used in production however this is my first scenario where I am using dates other than date.now() as a default value.
What is the correct body for the date parser in order for mongodb/ the mongoose driver to push a date into a Date type?
Any string that JavaScript's Date.parse method can parse will work as the string is cast to a Date by Mongoose using this function which calls the Date constructor which uses Date.parse to parse strings.
Related
so i know there is something called TTL in mongo but i dont think it will work for what i want to do, i want to set a document from my schema where the default value is basic but when the customer pays his membership i want to set it to "plus" i did that query in my controller, but i want to know if there is a way to make this document when the value is "plus" to have an expiration time, like 1 week or 1 month, and when the time is out set it again to basic, there is the schema
const UserSchema = new Schema({
username: {type: String, required: true},
nombre_empresa: {type: String},
email: {type: String, required: true, unique: true},
password: {type: String, required: true},
tipo_cuenta: {type: String, required: true},
isNewUser: {type: String, default: 'basic'}
},
{
timestamps: true
},
{
typeKey: '$type'
});
and here the process when i change his status
userCtrl.renderMembershipSucess = async (req, res) => {
const status = 'plus'
const status_basic = 'basico'
const status_user = await User.findByIdAndUpdate(
req.user.id, {
$set: { isNewUser: status }
}
)
console.log(status_user)
res.render('users/sucess')
}
Rather than relying on a trigger that must fire and correctly update the user records, store the expiration and check it when determining if the user is plus or not.
For example, you might add a plusExpires field to the user schema with a default value of null. When you upgrade the user to plus, set plusExpires to the Date that it should no longer be valid.
Add an instance method to the schema to perform that check:
UserSchema.methods.isPlus = function() {
return this.isNewUser == "plus" && (( this.plusExpires == null ) || (this.plusExpires > new Date())
}
Then any time you need to test if a user is plus or not, just call User.isPlus() on the user object.
i dont think there mongodb provide a built-in way to do what you want, however you can run a cronjob every midnight to fetch your "plus" customers, check their membership and update it if necessary.
another way maybe to design your mongodb collections to leverage the TTL, you can separate the User and PlusMembership collections, when a user make a payment, insert a PlusMembership data with TTL
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.
my schema in node js
var itemSchema = new mongoose.Schema({
name: { type: String, required: true },
value: { type: String }
});
while doing find, the following result comes,
Item.find().exec(callback); gives result
[{"one":1},{"two":2},{"three":1},{"four":1}]
but i want the result like this,
[{"one":1,"two":2,"three":3,"four":4}]
Is there only way iterate and form the result ?
Please suggest me!
For my project i've created an userSchema which simplified looks like the following:
var userSchema = new Schema({
_id: String,
screenname: {type: String, required: false, default: "equal _id"},
});
The user has an _id that is a string which also is his username.
Everything works so far until i tried to add an extra field screenname. What i want is when the user creates an account, his screenname equals the value of _id. Later he can adjust it but by default it should equal the value of _id. i've also tried :
screenname: {type: String, required: false, default: _id},
But than ofcourse _id is not defined.
How should i set the default value to equal another value ?
use the pre middleware explained here
userSchema.pre('save', function (next) {
this.screenname = this.get('_id'); // considering _id is input by client
next();
});
You can pass a function to default, following is a schema field excerpt:
username: {
type: String,
required: true,
// fix for missing usernames causing validation fail
default: function() {
const _t = this as any; // tslint:disable-line
return _t.name || _t.subEmail;
}
},
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.