I'm having some trouble setting up a cron job with percolate:synced-cron package to expire collection entries based on simple schema date and time fields. Is there another way to do this, or am I doing something wrong?
I'm receiving the following error below:
TypeError: Posts.find(...).toArray is not a function
Synced Cron Code
SyncedCron.start();
SyncedCron.add({
name: 'Expire Events',
schedule: function(parser) {
// parser is a later.parse object
return parser.text('every 15 minutes');
},
job: function() {
expireToday = Posts.find ({
date: new Date().toISOString().substring(0,10)
}).toArray();
console.log(expireToday);
for (i = 0; i < expireToday.length; i++) {
expireId = expireToday.eq(i)._id;
console.log(expireId);
if (expireToday.eq(i).time < new Date().toTimeString().substring(0,5)) {
Posts.deleteOne({_id : expireId});
}
}
}
});
Simple Schema Coffee Code
Schemas.Posts = new SimpleSchema
title:
type:String
max: 60
optional: true
content:
type: String
optional: true
autoform:
rows: 5
createdAt:
type: Date
autoValue: ->
if this.isInsert
new Date()
updatedAt:
type:Date
optional:true
autoValue: ->
if this.isUpdate
new Date()
time:
type: String
optional: false
autoform:
afFieldInput:
type: 'time'
date:
type: String
optional: false
autoform:
afFieldInput:
type: 'date'
owner:
type: String
regEx: SimpleSchema.RegEx.Id
autoValue: ->
if this.isInsert
Meteor.userId()
autoform:
options: ->
_.map Meteor.users.find().fetch(), (user)->
label: user.emails[0].address
value: user._id
Example mongo date and time
"date" : "2017-09-10"
"time" : "01:01"
The error message is telling you that this failed:
expireToday = Posts.find ({
date: new Date().toISOString().substring(0,10)
}).toArray();
It means that your Posts.find() didn't return anything that could be converted to an array.
It returns a cursor, maybe you meant to add a .fetch() to get an array of objects?
In either case you should check the return of a call like this to make sure it is returning what you expect - just basic defensive coding practice
See this related post
Going from dates to strings isn't great for searching in mongodb. If you want documents that expire today then you want to define today as going from midnight to midnight. You can also delete in bulk when running code on the server (SyncedCron jobs always run on the server).
SyncedCron.add({
name: 'Expire Events',
schedule: function(parser) {
return parser.text('every 15 minutes');
},
job: function() {
let todayStart = new Date();
todayStart.setHours(0,0,0,0);
let todayEnd = todayStart.setHours(23,59,59,999);
Posts.remove ({ date: {$gte: todayStart, $lte: todayEnd });
}
});
But this assumes you are storing datetimes in mongodb datetime fields, not as strings (which by the way, you should absolutely do, if nothing else but to gain timezone support).
If you want to use your schema with your date and time as strings then you can do:
SyncedCron.add({
name: 'Expire Events',
schedule: function(parser) {
return parser.text('every 15 minutes');
},
job: function() {
let today = new Date().toISOString().substring(0,10);
let now = new Date().toTimeString().substring(0,5);
Posts.remove ({ date: today, time: { $lte: now });
}
});
Related
I have a controller where I am trying to query the most popular posts within the last week, sorted by most popular, and has a max cap of 50 posts. I am trying to use the aggregate() method; however, I am not sure if I am doing it correctly. When I run the query In insomnia I get an error like so:
{
"ok": 0,
"code": 8000,
"codeName": "AtlasError"
}
Here is my post model:
const postSchema = mongoose.Schema({
title: {
type: String,
required: true
},
message: {
type: String,
required: true
},
//replace creator with name
name: String,
creator: String,
tags: [String],
size: String,
selectedFile: String,
likes: {
type: [String],
default: [],
},
comments: {
type: [String],
default: []
},
createdAt: {
type: Date,
default: new Date(),
},
dogTreats: {
type: Number,
default: 0,
required: false,
}
});
and here is my controller/post.js
export const getPopular = async (req, res) => {
//get current time
let currentTime = new Date()
//get from 7 days ago
currentTime.setDate(currentTime.getDate()-7)
console.log(currentTime) // -> output 2022-09-04T19:29:39.612Z
try {
//sort posts by most likes and within 7 days ago, but with a max of 50 posts
const mostPopular = await PostMessage.aggregate([{"$sort": { likes: -1}}, { "$limit": 50}, { "$gt": currentTime }])
res.status(200).json(mostPopular)
} catch (error) {
res.status(500).json(error)
}
}
You can use find method. It is better to use here.
If you need to reach a value from another table populated, aggregation is better to use. However, at here, find is the best way to reach datas.
const mostPopular = await PostMessage.find({createdAt: {$gt : currentTime}}).sort({likes: -1}).limit(50)
Try this aggregation
export const getPopular = async (req, res) => {
//get current time
let currentTime = new Date()
//get from 7 days ago
currentTime.setDate(currentTime.getDate() - 7)
console.log(currentTime) // -> output 2022-09-04T19:29:39.612Z
try {
//sort posts by most likes and within 7 days ago, but with a max of 50 posts
const mostPopular = await PostMessage.aggregate([
{ $match: { createdAt: { $gt: currentTime } } },
{ $sort: { likes: -1 } },
{ $limit: 50 }
])
res.status(200).json(mostPopular)
} catch (error) {
res.status(500).json(error)
}
}
I have this model:
const HistorySchema = new Schema({
// Other fields
date: {
type: Date,
default: Date.now,
},
});
I am using an aggregate query to get some data and trying to format the date in the same time:
const final_project_option = {
$project: {
// Other projections
date: {
$dateFromString: {
date: "$date",
},
},
},
};
const pipeline = [
// Other options
final_project_option,
];
const history_events_with_aggregate = await History.aggregate(pipeline);
But, I am receiving this error:
error MongoError: $dateFromString requires that 'dateString' be a
string, found: date with value 2021-07-06T12:24:45.707Z
Any idea what's going on?
I need to get each user's transactions every three days. I want to know users that don't have up to a certain amount(200) within the three days period, then get the sum of all the transactions for each user. I want to exclude Sunday since transactions are always low on Sundays.
I want to make sure this is done right from the DB because the transactions from each user can run into thousands even millions.
I am using dayjs to manipulate the time but I am not getting it right
I have been able to get the three previous date and the current date. The previous date will be the startDate and the current date will be endDate.
But I need to remove if Sunday is in the range and use that to query the database.
This is what I have done what I am not close to fixing it.
How can I query the transaction table by dateCreated and exclude sundays?
schema sample
export const TransactionSchema = new mongoose.Schema({
description: {
type: String
},
ref: {
type: String,
required: true
},
userID: {
type: mongoose.SchemaTypes.ObjectId,
ref: 'User'
},
amount: {
type: Number,
required: true,
},
commission: {
type: Number,
default: 0
},
responseDescription: {
type: String
},
authCode: {
type: Number
},
isDeleted: {
type: Boolean,
default: false
},
dateCreated: {
type: Date,
default: Date.now
},
dateUpdated: {
type: Date,
required: false
},
openingBalance: {
type: Number
},
closingBalance: {
type: Number
},
})
method
async getUserRequiredTargetTrans() {
let now = dayjs();//endDate
let fromThreeDays = now.subtract('2', 'day')
let sunday = now.day(0)
let withOutSunday = now.diff(fromThreeDays);//startDate
const response = await this.transactionModel.find({ isDeleted: false, dateCreated: { $gte: withOutSunday, $lt: now } })
To exclude sundays from date range, you can use $where operator like this:
async getUserRequiredTargetTrans() {
let from = dayjs();//endDate
let fromThreeDays = now.subtract('2', 'day')
const response = await this.transactionModel.find({ isDeleted: false, dateCreated: { $gte: fromThreeDays, $lt: now },
// exculde sunday
$where: `function() { return this.dateCreated.getDay() !== 0;}`
} )
You pass a dayjs, don't know whether you can use it directly. Perhaps you have to use
find({ isDeleted: false, dateCreated: { $gte: withOutSunday.toDate(), $lt: now.toDate() } })
I have the following sub-documents :
{
id: 1,
date:2019-04-01 00:21:19.000
},
{
id: 2,
date:2019-03-31 00:21:19.000
} ...
Document schema is :
const barEventSchema = new Schema({
id: {
type: Number,
unique: true,
required: true
},
raw: { type: String },
date: { type: Date },
type: { type: String },
})
const FooSchema = new Schema({
bar: [barEventSchema]
})
I want to do a query based on a date range picked from html input, which has values like 2019-04-01, 2019-03-31.
So on serverside, I want to do something like:
//#star_date = 2019-04-01, #end_date = 2019-04-01
Foo.findOne('bar.date' : {$lte : start_date, $gte: end_date})
However, this returns all the documents.
All documents having any subdocument with date between start and end date range can be retrieved using:
const conditions = {
'bar': {
$elemMatch: {
'date': {
$gte: new Date(start_date),
$lte: new Date(end_date)
}
}
}
}
Foo.find(conditions)
This will return all the documents where there is at least a subdocument having its date between the range specified in condition.
The $elemMatch operator is used to effect this condition on the date field of the bar subdocument.
I have this mongoose schema
const postSchema= new Schema({
body:{ type: String, required:true, validate:bodyValidators},
createdBy: { type: String},
to: {type:String, default:null },
createdAt: { type:Date, default:Date.now()},
likes: { type:Number,default:0},
likedBy: { type:Array},
dislikes: { type:Number, default:0},
dislikedBy: { type:Array},
comments: [
{
comment: { type: String, validate: commentValidators},
commentator: { type: String}
}
]
});
every posts on my app is returns Aug 20, 2017 at 10:01 PM but where i am it's 2 hours more.
here's the HTML, i'm using Angular4.
{{post.createdAt | date: 'MMM dd, yyyy'}} at {{post.createdAt | date:'shortTime'}}
I just can't understand why
Mongoose is receiving the value calculate at the time you start it, instead of the function. You should pass it the function instead of running it. Whenever you use parenthesis you are executing the function instead of referencing it. I had the same problem once.
In mongoose you can do like following. Using update() or findOneAndUpdate()
with {upsert: true} option
you can use $setOnInsert without having to pass them in everytime new MyModel() is called.
var update = {
updatedAt: new Date(),
$setOnInsert: {
createdAt: new Date()
}
};
You have assigned the value in the wrong way. try this:
createdAt: {
type: Date,
default: Date.now
}
Read this link for further understanding:
http://mongoosejs.com/docs/guide.html