MongoDB Count By Current Month - javascript

I'm new to MongoDB. I need to get the count of the posts which are posted in this current month. PlateModel is my model I've kept timestamps true also. It looks like the below:
{ timestamps: true }
My present code in the Controller looks like below:
const today = new Date();
const host_count = await PlateModel.find({
$and: [
{
postedBy: req.user._id,
},
{
createdAt: today.getMonth(),
},
],
}).count();
But, I get the count value 0. Can anyone help me to figure out the problem?

You could filter the objects from the start of the current month to the end of the next month:
const startOfCurrentMonth = new Date();
startOfCurrentMonth.setDate(1);
const startOfNextMonth = new Date();
startOfNextMonth.setDate(1);
startOfNextMonth.setMonth(startOfNextMonth.getMonth() + 1);
const host_count = await PlateModel.find({
$and: [
{
postedBy: req.user._id,
},
{
createdAt: {
$gte: startOfCurrentMonth,
$lt: startOfNextMonth
}
},
],
}).count();

You can use the Moment library.
const moment = require("moment");
const firstdate = moment().startOf('month').format('DD-MM-YYYY');
console.log(firstdate);
const lastdate=moment().endOf('month').format("DD-MM-YYYY");
console.log(lastdate);
const host_count = await PlateModel.find({
$and: [
{
postedBy: req.user._id,
},
{
createdAt: {
$gte:firstdate,
$lt:lastdate
}
},
],
}).count();

Related

check date existence on array of string

This is my dataset from MongoDB Collection:
{
"_id": "60c0ace96e93993880efd337",
"lv": [
uid: 1,
"createdate": "2021-12-15T12:30:01.935Z",
"updatedAt": [
"2021-12-15T12:31:11.635Z",
"2021-12-15T12:31:51.955Z",
"2021-12-16T12:30:01.935Z",
"2021-12-16T12:30:01.935Z",
"2021-12-17T12:30:01.935Z",
"2021-12-18T12:30:01.935Z"
]
]
},
{
...
}
I want to filterout only the data which date range lies in createdate column or updatedAt column.
I am not able to get the desired result. Not getting the idea that where I am making the mistake in the query or coed.
What I have tried I will mention here.
let startA = new Date("2021-12-14");
const a = new Date(startA.setHours(startA.getHours() - 5));
const start = new Date(a.setMinutes(startA.getMinutes() - 30));
let endA = new Date("2021-12-17");
const b = new Date(endA.setHours(endA.getHours() - 5));
const end = new Date(b.setMinutes(endA.getMinutes() - 30));
const fetchData = await MyCollection.findOne(
{
_id: ObjectId(req.body.id),
'lv.createdate': { $gte: start, $lt: end },
'lv.updatedAt': {
$elemMatch: { $gte: start, $lt: end }
}
}
).lean().exec();
Any help or suggestion is really appreciated. Thanks in advance for the interaction.
Your input data is not valid. With some assumptions, the solution could be this one:
db.MyCollection.aggregate([
{
$set: {
lv: {
$map: {
input: "$lv",
as: "lv",
in: {
$filter: {
input: "$$lv.updatedAt",
cond: {
$and: [
{ $gte: ["$$this", start] },
{ $lt: ["$$this", end] }
]
}
}
}
}
}
}
}
])
or this one:
db.MyCollection.aggregate([
{
$set: {
"lv.updatedAt": {
$filter: {
input: "$lv.updatedAt",
cond: {
$and: [
{ $gte: ["$$this", start] },
{ $lt: ["$$this", end] }
]
}
}
}
}
}
])

how to get data between the date range in javascript

I would like to know how to get data between date range in javascript
I have object array obj and variables sdate and edate,
how to get array object if the cdate falls between the range sdate and edate
function getdate(){
var finals=[];
var result = obj.orders.filter(e=>{
if(e.cdate < sdate && e.cdate > edate){
finals.push(e);
}
})
}
var obj={
orders:[
{id:1, mode: "xyz", orderid: 123, cdate: "2017-2-13 07:33:30"},
{id:2, mode: "abc", orderid: 456, cdate: "2018-4-20 06:10:30"},
{id:3, mode: "xyz", orderid: 768, cdate: "2020-8-10 08:00:00"}
]
}
var sdate="11-5-2020"
var edate="20-2-2021"
Expected Output
[
{id:3, mode: "xyz", orderid: 768, cdate: "2020-8-10 08:00:00"}
]
In your attemot you are comparing your sdate and edate with cdate node from the onjects in array. This will berform only string comparison, since both of them are strings. To perform Date comparison, you have to convert both of them into Date objects. Your cdate is a standard date object, so new Date() will retun the date object for the string.
But your sdate and edate are not valid date strings. So I have splitted them and created new date object using that. Comparing the date objects will provide you the expected result.
Also I have set hours of endDate to 23, 59, 59, 999. This is to ensure that if a date in array comes with the same date as end date, that should be filtered out. Because that is the maximum value for end date for the particular day.
Also you dont need to push finals.push(e) inside the filter function. Instead you could simply return the status of that comparison inside your filter. This will generate a new array. This will be your expected result.
Your logic for calculating the value inbetween two dates is wrong. i have corrected that aswell.
var sdate = "11-5-2020";
var edate = "20-2-2021";
var obj = {
orders: [
{ id: 1, mode: "xyz", orderid: 123, cdate: "2017-2-13 07:33:30" },
{ id: 2, mode: "abc", orderid: 456, cdate: "2018-4-20 06:10:30" },
{ id: 3, mode: "xyz", orderid: 768, cdate: "2020-8-10 08:00:00" }
]
}
function getdate() {
var finals = [];
const [sDay, sMonth, sYear] = sdate.split('-');
const [eDay, eMonth, eYear] = edate.split('-');
const startDate = new Date(sYear, +sMonth - 1, sDay);
const endDate = new Date(eYear, +eMonth - 1, eDay, 23, 59, 59, 999);
var result = obj.orders.filter(e => (new Date(e.cdate) >= startDate && new Date(e.cdate) <= endDate));
return result;
}
console.log(getdate());
Please Note You can perform string comparison with dates if they are in standard ISO format. If your want to make use of that, you need to make the start and end date to iso format and perfrom comparison. So the filter statement will be
var result = obj.orders.filter(e => e.cdate >= startDate.toISOString() && e.cdate <= endDate.toISOString());
You have several issues
Wrong test for between: date >= sdate && date <= edate is what you need
If you cannot change the sdate, edate and the object dates, you can still format and still do string manipulation which is faster and safer than date manipulation due to timezones and daylight savings times
let obj={
orders:[
{id:1, mode: "xyz", orderid: 123, cdate: "2017-2-13 07:33:30"},
{id:2, mode: "abc", orderid: 456, cdate: "2018-4-20 06:10:30"},
{id:3, mode: "xyz", orderid: 768, cdate: "2020-8-10 08:00:00"}
]
}
const getyyyymmdd = str => {
const parts = str.split(" ")[0].split("-")
return parts[0].length === 2 ? `${parts[2]}-${parts[1].padStart(2, '0')}-${parts[0].padStart(2, '0')}` : `${parts[0].padStart(2, '0')}-${parts[1].padStart(2, '0')}-${parts[2]}`
}
function getdate(sdate,edate){
sdate = getyyyymmdd(sdate)
edate = getyyyymmdd(edate)
return obj.orders.filter(({cdate}) => {
cdate = getyyyymmdd(cdate);
return cdate >= sdate && cdate <= edate
})
}
console.log(getdate("11-5-2020","20-2-2021"))
Alternatively if you can change either of the dates, you can add leading 0s to the object and swap the order of the start and end date
let obj={
orders:[
{id:1, mode: "xyz", orderid: 123, cdate: "2017-02-13 07:33:30"},
{id:2, mode: "abc", orderid: 456, cdate: "2018-04-20 06:10:30"},
{id:3, mode: "xyz", orderid: 768, cdate: "2020-08-10 08:00:00"}
]
}
function getdate(sdate,edate){
return obj.orders.filter(item => {
return item.cdate.split(" ")[0] >= sdate && item.cdate.split(" ")[0] <= edate
})
}
console.log(getdate("2020-05-11","2021-02-20"))
You can get the desired result by first converting the string into Date object by passing the string in right format using helper function createDateObj.
Then using filter and get the result as
return arr.filter((o) => {
const date = new Date(o.cdate);
return date - start > 0 && end - start > 0;
})
var sdate = "11-5-2020";
var edate = "20-2-2021";
function createDateObj(str) {
const [a, b, c] = str.split("-");
return `${b}-${a}-${c}`;
}
function getdate(arr) {
const start = new Date(createDateObj(sdate));
const end = new Date(createDateObj(edate));
return arr.filter((o) => {
const date = new Date(o.cdate);
return date - start > 0 && end - start > 0;
});
}
var obj = {
orders: [
{ id: 1, mode: "xyz", orderid: 123, cdate: "2017-2-13 07:33:30" },
{ id: 2, mode: "abc", orderid: 456, cdate: "2018-4-20 06:10:30" },
{ id: 3, mode: "xyz", orderid: 768, cdate: "2020-8-10 08:00:00" },
],
};
console.log(getdate(obj.orders));

Getting the occurences of a date in a specific week

I would like to get the occurences of a day in a specific week (the week that includes today). I have an array of visits with a specified location and date that I want to transform.
const today = new Date(Date.parse("2021-05-13")); // set today
const numDay = today.getDate();
const twoDaysAgo = new Date();
twoDaysAgo.setDate(numDay - 2); // set 2 days ago from today
const twelveDaysAgo = new Date();
twelveDaysAgo.setDate(numDay - 12); // set 12 days ago from today
const visits = [{
location: "Paris",
date: today
},
{
location: "Berlin",
date: twoDaysAgo
},
{
location: "Brussels",
date: twoDaysAgo
},
{
location: "Rome",
date: twelveDaysAgo
}
];
I would like to process the data so that the number of times a day occurs in the specific week can be tracked as a number and the locations are stored in an array. If there are no visits for a certain day, they do not need to be stored and it should just say numVisits: 0.
This is the outcome I would like to achieve.
const thisWeekResult = [{
monday: {
numVisits: 0
},
tuesday: {
numVisits: 2,
locations: ["Berlin", "Brussels"]
},
wednesday: {
numVisits: 0,
},
thursday: {
numVisits: 1,
locations: ["Paris"]
},
friday: {
numVisits: 0,
},
saturday: {
numVisits: 0,
},
sunday: {
numVisits: 0,
}
}];
You could start with the beginning of the week (start in the code below being sunday just gone).
Then you reduce the 7 days beyond that date, and look for records on that dat from the original set using filter. Finally you just build up the object required for each day
const today = new Date(Date.parse("2021-05-13")); // set today
const numDay = today.getDate();
const twoDaysAgo = new Date();
twoDaysAgo.setDate(numDay - 2); // set 2 days ago from today
const twelveDaysAgo = new Date();
twelveDaysAgo.setDate(numDay - 12); // set 12 days ago from today
const visits = [{
location: "Paris",
date: today
},
{
location: "Berlin",
date: twoDaysAgo
},
{
location: "Brussels",
date: twoDaysAgo
},
{
location: "Rome",
date: twelveDaysAgo
}
];
const start = new Date()
start.setDate(today.getDate() - today.getDay())
const result = [1,2,3,4,5,6,7].reduce( (acc,d) => {
const date = new Date()
date.setDate(start.getDate() + d);
const day = new Intl.DateTimeFormat('en', {weekday:'long'}).format(date).toLowerCase();
const records = visits.filter(v => v.date.getYear() == date.getYear() && v.date.getMonth() == date.getMonth() && v.date.getDate() == date.getDate());
acc[day] = records.length
? {
numVisits: records.length,
locations: records.map(r => r.location)
}
: {numVisits: 0 };
return acc;
},{});
console.log(result);

Count array items by month and year

I am getting dates in json of multiple parcels. the dates usually tells on which date and time that particular parcels was created. So with that date I want to count number of parcels created in each month. I have never done this before and i am not sure what thread of stackoverflow can help me out in this regard. I would very much appreciate any explanation to solve this help or a code reference.
Here is my sample JSON result
[
{
"createdAt": "2019-12-30T04:36:05.001Z"
},
{
"createdAt": "2019-12-06T08:58:23.030Z"
},
{
"createdAt": "2020-01-08T19:00:21.873Z"
},
{
"createdAt": "2020-01-10T14:55:50.781Z"
},
{
"createdAt": "2019-12-21T13:05:09.983Z"
},
{
"createdAt": "2020-01-15T12:10:20.316Z"
},
{
"createdAt": "2020-01-14T06:47:36.078Z"
},
{
"createdAt": "2020-02-15-T06:47:36.078Z"
}
]
I am working with angular so i am getting this data from my service. So now i need to show month wise total number of parcels created.
You could get a part of the ISO 8601 date string as key and count with an object.
var data = [{ createdAt: "2019-12-30T04:36:05.001Z" }, { createdAt: "2019-12-06T08:58:23.030Z" }, { createdAt: "2020-01-08T19:00:21.873Z" }, { createdAt: "2020-01-10T14:55:50.781Z" }, { createdAt: "2019-12-21T13:05:09.983Z" }, { createdAt: "2020-01-15T12:10:20.316Z" }, { createdAt: "2020-01-14T06:47:36.078Z" }, { createdAt: "2020-02-15-T06:47:36.078Z" }],
result = data.reduce((r, { createdAt }) => {
var key = createdAt.slice(0, 7);
r[key] = (r[key] || 0) + 1;
return r;
}, {});
console.log(result);
You can use Array.prototype.reduce() to summarize your records.
const src = [{"createdAt":"2019-12-30T04:36:05.001Z"},{"createdAt":"2019-12-06T08:58:23.030Z"},{"createdAt":"2020-01-08T19:00:21.873Z"},{"createdAt":"2020-01-10T14:55:50.781Z"},{"createdAt":"2019-12-21T13:05:09.983Z"},{"createdAt":"2020-01-15T12:10:20.316Z"},{"createdAt":"2020-01-14T06:47:36.078Z"},{"createdAt":"2020-02-15T06:47:36.078Z"}],
summary = src.reduce((res,{createdAt}) => {
const year = new Date(createdAt).getFullYear(),
month = new Date(createdAt).getMonth()+1
res[`${year}-${month}`] = (res[`${year}-${month}`] || 0) + 1
return res
}, {})
console.log(summary)
Note, above will work if your createdAt strings formatted in any way that may be parsed by new Date() constructor, not only ISO-formatted date.

NodeJS: Get Count By Month-Year

I have some transactional data which looks as below:
[{UserId: 19156, createdAt: "2014-03-01T18:30:00.000Z", …},
{UserId: 19150, createdAt: "2014-03-09T18:30:00.000Z", …},
{UserId: 18459, createdAt: "2014-04-09T18:30:00.000Z", …},
{UserId: 19666, createdAt: "2014-10-24T07:12:05.000Z", …}]
My requirement it to get count by month-year, so that the output looks like below:
[{period: '2014-03', count:2}
{period: '2014-04', count:1},
{period: '2014-10', count:1}]
I'm doing this in Nodejs, and am just not able to work with the date to make this happen.
Can you please help?
You can use the code given below to group based on period year and month.
let array = [{ UserId: 19156, createdAt: "2014-03-01T18:30:00.000Z" },
{ UserId: 19150, createdAt: "2014-03-09T18:30:00.000Z" },
{ UserId: 18459, createdAt: "2014-04-09T18:30:00.000Z" },
{ UserId: 19666, createdAt: "2014-10-24T07:12:05.000Z" }]
function count(array) {
return array.reduce((total, elem) => {
let temp = elem.createdAt.split("-")
let groupKey = temp[0] + "-" + temp[1];
total[groupKey] ? total[groupKey] +=1: total[groupKey] = 1;
// total[groupKey] += 1;
return total
}, {})
}
console.log(count(array))
The output of code above will be
{ '2014-03': 2, '2014-04': 1, '2014-10': 1 }
Of course you can easily convert from JSON format to array format using code given below
function convertToArray(json_data) {
let result = [];
for (var i in json_data)
result.push({ period: i, count: json_data[i] });
return result;
}
The output will be
[ { period: '2014-03', count: 2 },
{ period: '2014-04', count: 1 },
{ period: '2014-10', count: 1 } ]
You can take the substring of date , take the unique and count the frequency of each date
const arr = [{UserId: 19156, createdAt: "2014-03-01T18:30:00.000Z",},
{UserId: 19150, createdAt: "2014-03-09T18:30:00.000Z"},
{UserId: 18459, createdAt: "2014-04-09T18:30:00.000Z"},
{UserId: 19666, createdAt: "2014-10-24T07:12:05.000Z"}]
//take substring and just grab unique date
let distict_dates = [...new Set(arr.map(a => a.createdAt.substring(0, 7)))];
//count each date frequency
let reduced = distict_dates.map(a => {
return {
userCount: arr.filter(a1 => a1.createdAt.startsWith(a)).length,
createdAt: a
}
}
)
console.log(reduced);
You need this method basically:
.reduce((acc = {}, i) => {
let period = i.createdAt.slice(0,7);
acc[period] = {period, count: acc[period] ? acc[period].count+1: 1}
return acc;
}, {})
let t = [{UserId: 19156, createdAt: "2014-03-01T18:30:00.000Z"},
{UserId: 19150, createdAt: "2014-03-09T18:30:00.000Z"},
{UserId: 18459, createdAt: "2014-04-09T18:30:00.000Z"},
{UserId: 19666, createdAt: "2014-10-24T07:12:05.000Z"}].reduce((acc = {}, i) => {
let period = i.createdAt.slice(0,7);
acc[period] = {period, count: acc[period] ? acc[period].count+1: 1}
return acc;
}, {})
console.log(t);
// if you need exact same result then do it like this
console.log(Object.values(t));
using aggregation:
db.collectionName.aggregate([
{
$project:{
period:{$dateToString:{format:"%Y-%m",date:"$createdAt"}}
}
},{
$group:{ _id : {period : "$period"},count:{$sum:1}}
},
{ $sort : { _id : 1 } }
]);
You can try this:
db.doc.aggregate([{ $group: {
_id:null,
period: {
$dateToString: { format: "%Y-%m", date: "$createdAt" } },
count: { $sum: 1 } },
]
).then()
If the createdAt is a string, convert string to date as follows
var t = Date.parse("2015-04-01T18:30:00.000Z");
var date = new Date(d)
Now get the year and month as follows
date.getMonth() // zero indexed
date.getFullYear()
Append them and form your required string format for createdAt

Categories