how to use datetime in sails model - node.js

i would like to have a function in my controller to get data based on time range. First, i have all the data in mongodb, there is a attribute ModifiedTime as string looks like 2015-02-25T17:17:33Z. Second, i define the model in sails with ModifiedTime:
{ type: 'datetime', columnName: 'ModifiedTime' }
In the model.js, I set schema: true. Then in my controller, i try to use
User.find({ModifiedTime : {'<=' : new Date('2015-03-18T00:00:00Z')}}).exec(function(err,st){
if (err) return res(err);
if (!st) return res(new Error('Invalid ModifiedTime.'));
return res.json(st);
} );
But i get nothing, see always [] in the browse. I used waterline http://localhost:1337/User to check the data in browse. i can see all the data from mongodb. The strange thing is, i see something like ModifiedTime": "2015-02-18T17:36:53Z. so, for me, it looks like the ModifiedTime in sails is still a string, am i right? but i set the type as datetime in the model. I hope, it could transfer the string of mongodb to datetime in background, won't it? Please give some advise. i spend already too much time for that :(
thank you very much!
WJS

You're right / wrong.
In your DB you state the datetime is a string. If it is already a string then you can't set it to be a date in your sails model. You should simply compare two strings instead of transforming 2015-03-18T00:00:00Z into a date.
User.find({ModifiedTime : {'<=' : '2015-03-18T00:00:00Z'}}).exec(function(err,st){
if (err) return res(err);
if (!st) return res(new Error('Invalid ModifiedTime.'));
return res.json(st);
} );
If you truley want to use Date/Time then you must go through your original data and change modified time to a date/time object.

Related

Nestjs/Prisma not saving date number correctly

When I console log the response body right before I save it to the database, my response body shape looks correct. See below
//console.log response body
CreateOpenHourDto {
day: 'WEDNESDAY',
startTime: 1663858800000,
endTime: 1663878600000,
calendarId: 1
}
However, whenever I go into prisma studio and check the new db entry, the startTime, endTime is differnt.
There is nothing I have done to transform the data. Any tips are appreciated.
I am using
nestjs, prisma, postgres sql
My prisma model listed start and end times as "int" types and it should have been BigInt. For anyone that plans on using bigint. Be aware
Prisma returns records as plain JavaScript objects. If you attempt to use JSON.stringify on an object that includes a BigInt field, you will see the following error:
Do not know how to serialize a BigInt
To work around this issue, use a customized implementation of JSON.stringify:
JSON.stringify(
this,
(key, value) => (typeof value === 'bigint' ? value.toString() : value) // return everything else unchanged
)
This sounds hacky but its coming straight form the documentation as of the time of this comment.
https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields#working-with-bigint

Watch MongoDB to return changes along with a specified field value instead of returning fullDocument

I'm using watch() function of mongo to listen to changes made to a replicaSet, now I know I can get the whole document (fullDocument) by passing { fullDocument: 'updateLookup' } to the watch method,
like :-
someModel.watch({ fullDocument: 'updateLookup' })
But what I really want to do is, get just one extra field which isn't changed every time a new update is made.
Let's say a field called 'user_id', currently I only get the updatedFields and the fullDocument which contains the 'user_id' along with a lot of other data which I would like to avoid.
What I have researched so far is Aggregation pipeline but couldn't figure out a way to implement it.
Can anybody help me figure out a way to this?
Thanks everyone for suggesting, as #D.SM pointed out I successfully implemented $project
Like this :-
const filter = [{"$match":{"operationType":"update"}}, {"$project":{"fullDocument.user_id": 1, "fullDocument.chats": 0, "fullDocument._id": 0, "fullDocument.first_name": 0, "fullDocument.last_name": 0 }}];
Then passed it to watch() method
Like:-
const userDBChange = userChatModel.watch(filter, { fullDocument: 'updateLookup' });
Now I'm only getting user_id inside fullDocument object when the operationType is update hence reducing the data overhead returned from mongo
Thanks again #D.SM and other's for trying to help me out ;)

Is it possible to refer to "this" document in Mongoose?

I'm using Mongoose in Node.js, and I am wondering if it is possible to refer to the currently selected document using "this" or a similar mechanism. Here is the use case I'm looking for :
Mongoose Schema :
const mySchema = mongoose.Schema({
position: Number,
date: Number,
lastEventDate: Number
});
Let's say that, at some point in time, an event occurs.
For a document selected through its position, I want to update "lastEventDate" to the document's date.
Here is my dream code :
myModel.findOneAndUpdate(
{position: myPosition},
{$set: {
'lastEventDate': THISDOCUMENT.date
}}
);
Note : I'm using $set here because the actual code updates subdocuments...
Is there a built-in "THISDOCUMENT" reference such as the one I'm dreaming of, to do it all in a single query ?
Or do I have to first query the value before updating the document (two queries).
Couldn't find anything on the web, and I'm quite the newbie when it comes to using "this".
Thanks for any kind of help !
[EDIT :] Precisions about the objective :
I am in a situation where I only have the position "myPosition" to identify the correct document, and I want to set "lastEventDate" to the same value as "date" for that document.
My question is about efficiency : is it possible to perform the update in a single upload query ? Or do I have to first download the "date" value before uploading it back to the "lastEventDate" key ?
Gathering all the information provided, I will venture on a possible answer!
You could try something like:
Your schema JS file
const mySchema = mongoose.Schema({
position: Number,
date: Number,
lastEventDate: Number
});
mySchema.methods.doYourThing(){
this.lastEventDate=this.date; //it will set the lastEventDate
}
mongoose.model("myModel", MySchema, "mycollection")
Now, whenever you call doYourThing(), the action wanted will take place, you call it after you have a instance of the mode.
This is from my own code
const token = user.generateJwt(expirationDate); //send a token, it will be stored locally in the browser
it is inside a function that return an instance of user, and in the model User I have done a function called generateJwt like I have showed, and we have something like this:
return jwt.sign(
{
_id: this._id, //this is created automatically by Mongo
email: this.email,
name: this.name,
exp: parseInt(expiry.getTime() / 1000, 10), //Includes exp as UNIX time in seconds
level: this.level,
lastLogin: this.lastLogin,
failedLogin: this.failedLogin
},
process.env.JWT_SECRET
); // DO NOT KEEP YOUR SECRET IN THE CODE!
It returns all the information of the user!
Please, do not hesitate to add comments and feebacks, I am not sure it is what you want, but that is why I have understood your request.
Anothe option is using Virtuals, they also have access to this.

how to update the field 'updated_at' of a sequelize model without modifiyng any attributes

I'm using sequelize 2.0.0 with PostgreSQL.
I would like to know if it's possible to update the field 'updated_at' of a model with one method. If yes, how can I achieve that?
For instance, in others frameworks, like Laravel, you have model.touch() to automatically update the 'updated_at' of a model.
I've already tried to use model.save() but as the sequelize doc says, calling this method without attributes does nothing. Also, in the doc, I didn't find anything that allow me to do what I need to do simply.
Thanks in advance for help.
Edit:
To give an example of what I'm trying to achieved, I've already had an instance of my model:
Model.findById(1).then(function(myInstance){
[...]
myInstance.update() //here, I didn't change any attributes of myInstance and I would like to update the field udpated_at without doing another query.
[...]
}):
The question is : How can I update the field updated_at of my previous instance with one method?
To update an instance value, you can use instance.set(key, value, [options]).
myInstance.set('updatedAt', new Date());
myInstance.save().then(function() {
// my nice callback stuff
});
The sequelize docs have a good example of doing an update query if you don't have an instance:
Post.update({
updatedAt: null,
}, {
where: {
deletedAt: {
$ne: null
}
}
});
My solution is a little hackey. I had to update a field on the instance to be different than what it was supposed to be, so that sequelize thought that the field changed, even if it didn't; and make sure the proper field data was passed in afterwards.
For example, let's say the variable myInstance has a field named title, and a variable data holds the unchanged (or new) title ( {title:"OLD_OR_NEW_TITLE"} ). If I add to the code myInstance.set('title', data.title+'_FAKE'), then when the update/save method is called ( myInstance.update(data) ), sequelize will think that the field has changed, even though it might not have.

sorting alpha with mongoose

I'm trying to sort via mongoose 3.6.20 and I am receiving some unexpected results.
I have a list of companies with a name. At first I thought that maybe it was sorting in a case sensitive way. Which based on articles, I expect was true.
I'm now using a virtual property to down case the sort field. However, I'm still getting unexpected results.
CompanySchema.virtual('name_lower').get(function(){
return this.name.toLowerCase();
});
and when I sort
Company.find().sort({ name_lower: 1 });
I'm getting it in the following order:
company name
google
company name (yes a duplicate for testing)
I'm also outputting the value of my virtual property and it looks right. There is no whitespace or funky characters that would result in the 2nd 'company name' from appearing after google.
Using nodejs, express, mongoose.
What am I missing or doing incorrectly?
Update:
Based on the information provided in the answers, I refactored my schema to include some normalized fields and hooked into the pre save event of my document, where I update those normalized fields and sort using them in all future queries.
CompanySchema.pre('save', function(next){
this.normalized_name = this.name;
});
Next, is in the schema I use:
var CompanySchema = mongoose.Schema({
...
normalized_name: { type: String, set: normalize },
...
});
Where normalize is a function that for now, returns a lowercase version of the value passed into it. However, this allows me to expand on it later really fast, and I can quickly do the same to other fields that I might need to sort against.
As of MongoDB v3.4, case insensitive sorting can be done using collation method:
Company.find()
.collation({locale: "en" }) //or whatever collation you want
.sort({name:'asc'})
.exec(function(err, results) {
// use your case insensitive sorted results
});
Unfortunately MongoDB and Mongoose does not currently support complex sorting, so there are 2 options:
As you said, create a new field with the names sanitized to be all lowercase
Run a big for loop over all the data and update each company name to it's lower case form:
db.CompanyCollection.find().forEach(
function(e) {
e.CompanyName = e.CompanyName.toLowerCase();
db.CompanyCollection.save(e);
}
)
or
db.CompanyCollection.update({_id: e._id}, {$set: {CompanyName: e.CompanyName.toLowerCase()
Please see Update MongoDB collection using $toLower and Mongoose: Sort alphabetically as well for more info.
I want to put out that in this hook:
CompanySchema.pre('save', function(next){
this.normalized_name = this.name;
});
You'll have to call next(); at the end, if you want the normalized_name to be saved in the database, so the pre save hook would look like:
CompanySchema.pre('save', function(next){
this.normalized_name = this.name;
next();
});
This answer seems to be more helpful to me. I had to consider diacritics along with the case so I had used strength:3.
Mongoose: Sort alphabetically

Resources