Selecting dates(mm-dd-yyyy) this month from mongodb - node.js

How can I select the dates from my mongodb for this month only, I have a date:{type:String} and my format is: mm-dd-yyyy ex: 09-03-2019:
Here is my router to get the distinct dates then count them, but not for monthly:
router.get('/blooddonationarea', function(req, res) {
sess=req.session;
Blooddonation.aggregate([{$group: {_id : "$date" , count :{$sum:1}}},{$sort: {_id: 1}}],function(err, date) {
res.json({ success: true, date: date });
});
});
yields to:
[ { _id: '04-11-2019', count6: 1 },
{ _id: '05-21-2019', count6: 1 },
{ _id: '10-11-2019', count6: 3 },
{ _id: '10-22-2019', count6: 1 } ]
My desired output is to display the dates for example where date = month.now() then it will only show months for 01-dd-yyyy only.
I tried this :
const startOfMonth = moment().startOf('month').format('MM-DD-YYYY')
const endOfMonth = moment().endOf('month').format('MM-DD-YYYY')
Blooddonation.aggregate([
{ "$match": {
"date": { "$gte": startOfMonth, "$lte": endOfMonth }
}},
{ "$group": { "_id": "$date", "count": { "$sum": 1 } } },
{ "$sort": { "_id": 1 } }],function(err, date) {
res.json({ success: true, date: date });
console.log("dates are" + date);
});
});

You can use moment library to get the desired format and then use $gte and $lte operator to get the data for the current month only
const moment = require('moment')
const startOfMonth = moment().startOf('month').format('MM-DD-YYYY')
const endOfMonth = moment().endOf('month').format('MM-DD-YYYY')
Blooddonation.aggregate([
{ "$match": {
"date": { "$gte": startOfMonth, "$lte": endOfMonth }
}}
{ "$group": { "_id": "$date", "count": { "$sum": 1 } } },
{ "$sort": { "_id": 1 } }
])

Related

Fetching last 30 days of Mongo records, summing by date, and filling in missing dates in range

I have a Mongo database filled with "Events" records, that look like this:
{
timestamp: 2022-03-15T22:11:34.711Z,
_id: new ObjectId("62310f16b0d71321e887a905")
}
Using a NodeJs server, I need to fetch the last 30 days of Events, grouped/summed by date, and any dates within that 30 days with no records need to be filled with 0.
Using this code I can get the correct events, grouped/summed by date:
Event.aggregate( [
{
$match: {
timestamp: {
$gte: start,
$lte: end,
}
}
},
{
$project: {
date: {
$dateToParts: { date: "$timestamp" }
},
}
},
{
$group: {
_id: {
date: {
year: "$date.year",
month: "$date.month",
day: "$date.day"
}
},
"count": { "$sum": 1 }
}
}
] )
This will return something like this:
[
{
"_id": {
"date": {
"year": 2022,
"month": 3,
"day": 14
}
},
"count": 3
},
{
"_id": {
"date": {
"year": 2022,
"month": 3,
"day": 15
}
},
"count": 8
},
]
I also have this Javascript code to generate the last 30 days of dates:
const getDateRange = (start, end) => {
const arr = [];
for(let dt = new Date(start); dt <= end; dt.setDate(dt.getDate() + 1)){
arr.push(new Date(dt));
}
return arr;
};
const subtractDays = (date, days) => {
return new Date(date.getTime() - (days * 24 * 60 * 60 * 1000));
}
const end = new Date();
const start = subtractDays(end, 30);
const range = getDateRange(start, end);
Which returns something like this:
[
2022-03-09T01:13:10.769Z,
2022-03-10T01:13:10.769Z,
2022-03-11T01:13:10.769Z,
2022-03-12T01:13:10.769Z,
2022-03-13T01:13:10.769Z,
...
]
It seems like I have all the pieces, but I'm having trouble putting all this together to do what I need in an efficient way. Any push in the right direction would be appreciated.
Whenever one has to work with date/time arithmetic then I recommend a library like moment.js
const end = moment().startOf('day').toDate();
const start = moment().startOf('day').subtract(30, 'day').toDate();
In MongoDB version 5.0 you can use $dateTrunc(), which is shorter than $dateToParts and { year: "$date.year", month: "$date.month", day: "$date.day" }
You need to put all data in an array ({$group: {_id: null, data: { $push: "$$ROOT" }}) and then at missing elements with $ifNull:
event.aggregate([
{
$match: {
timestamp: { $gte: start, $lte: end }
}
},
{
$group: {
_id: { $dateTrunc: { date: "$timestamp", unit: "day" } },
count: { $sum: 1 }
}
},
{ $project: {timestamp: "$_id", count: 1, _id: 0} },
{
$group: {
_id: null,
data: { $push: "$$ROOT" }
}
},
{
$set: {
data: {
$map: {
input: { $range: [0, 30] },
as: "i",
in: {
$let: {
vars: {
day: { $dateAdd: { startDate: start, amount: "day", unit: "$$i" } }
},
in: {
$ifNull: [
{
$first: {
$filter: {
input: "$data",
cond: { $eq: ["$$this.timestamp", "$$day"] }
}
}
},
{ timestamp: "$$day", count: 0 }
]
}
}
}
}
}
}
},
{ $unwind: "$data" }
])
$range operator supports only integer values, that's the reason for using $let. Otherwise, if you prefer to use the external generated range, it would be
{
$set: {
data: {
$map: {
input: range,
as: "day",
in: {
$ifNull: [
{
$first: {
$filter: {
input: "$data",
cond: { $eq: ["$$this.timestamp", "$$day"] }
}
}
},
{ timestamp: "$$day", count: 0 }
]
}
}
}
}
}
And for MongoDB version 5.1 you may have a look at $densify
Use aggregation stage densify if you're using MongoDB version 5.1 or later. But for lower version, below query can be used.
db.collection.aggregate([
{
$match: {
timestamp: {
$gte: {
"$date": "2022-03-01T00:00:00.000Z"
},
$lte: {
"$date": "2022-03-31T23:59:59.999Z"
},
}
}
},
{
$project: {
date: {
$dateToParts: {
date: "$timestamp"
}
},
}
},
{
$group: {
_id: {
date: {
year: "$date.year",
month: "$date.month",
day: "$date.day"
}
},
"count": {
"$sum": 1
}
}
},
{
"$group": {
"_id": null,
"originData": {
"$push": "$$ROOT"
}
}
},
{
"$project": {
"_id": 0,
"data": {
"$concatArrays": [
{
"$map": {
"input": {
"$range": [
0,
30,
1
]
},
"in": {
"$let": {
"vars": {
"date": {
"$add": [
{
"$date": "2022-03-01T00:00:00.000Z"
},
{
"$multiply": [
"$$this",
86400000
]
}
]
}
},
"in": {
"_id": {
"date": {
"day": {
"$dayOfMonth": "$$date"
},
"month": {
"$month": "$$date"
},
"year": {
"$year": "$$date"
}
}
},
"count": 0
}
}
}
}
},
"$originData"
]
}
}
},
{
"$unwind": "$data"
},
{
$group: {
_id: {
date: {
year: "$data._id.date.year",
month: "$data._id.date.month",
day: "$data._id.date.day"
}
},
"count": {
"$sum": "$data.count"
}
}
},
{
"$sort": {
"_id.date.year": 1,
"_id.date.month": 1,
"_id.date.day": 1
}
}
])
Link to online playground. https://mongoplayground.net/p/5I0I04HoHXm

Fill missing dates in records - Nodejs Mongoose

I'm using this query to get count of orders for 7 days of currently week. The result I get is something like this:
[
{ _id: '2021-01-31', orders: 3 },
{ _id: '2021-02-01', orders: 1 },
{ _id: '2021-02-02', orders: 2 },
{ _id: '2021-02-06', orders: 2 }
]
The problem is that if there was no order on specific day, the orders count should be 0 for that date. For example { _id: '2021-02-03', orders: 0 }, there was no order on 03-02-2021 it should be 0.
This is the query that I'm using:
let d = new Date()
d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay()||7));
let yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1));
let weekNumber = Math.ceil(( ( (d - yearStart) / 86400000) + 1)/7);
const ordersweekly = await Order.aggregate([
{
"$set": { "date": { "$week": "$createdAt" } }
},
{
"$match": { "date": weekNumber }
},
{
"$set": { "date": { "$dateToString": { "format": "%Y-%m-%d", "date": "$createdAt" } } }
},
{
"$group": { "_id": "$date", "orders": { "$sum": 1 } }
},
{ "$sort": { "_id": 1 } }
])

Query with string date format in mongodb

I have a data like below in my mongoDB collection. I want to count the total number or search_term on today basis.
_id:ObjectId("5b7e1d38981cdc1a7c8bb5fc")
search_term:"Baiyoke Boutique"
date:"August 23rd 2018, 9:34:32 am"
_id:ObjectId("5b7e1fa8fa27fd2754080ad9")
search_term:"Baiyoke Boutique"
date:"August 23rd 2018, 9:44:56 am"
_id:ObjectId("5b7e28314d2d0f388c1596cd")
search_term:"Baiyoke Florting Market"
date:"August 23rd 2018, 10:21:21 am"
I have tried following query. I have used moment. I am not what mistake I did.
var start = moment().startOf('day');
var end = moment().endOf('day');
history.find({
date: {
$gte: start,
$lt: end
}
}).count().toArray(
function (e, res) {
if (e) callback(e)
else callback(null, res)
});
You can try below queries in mongodb 3.6 and above
db.collection.find({
"$expr": {
"$gte": [{ "$dateFromString": { "dateString": "$date" }}, start.toDate() ],
"$lt": [{ "$dateFromString": { "dateString": "$date" }}, end.toDate() ]
}
}).count()
or with aggregation
db.collection.aggregate([
{ "$addFields": {
"date": {
"$dateFromString": {
"dateString": "$date"
}
}
}},
{ "$match": { "date": { "$gte": start.toDate(), "$lt": end.toDate() }}},
{ "$count": "count" }
])
You can try this
db.col.aggregate([{$addFields: {
convertedDate: { $toDate: "$date" }
}},
{"$match" :
{"convertedDate" :
{"$gte" : ISODate("2018-08-23T09:34:32.000Z"),
"$lte" : ISODate("2018-08-23T09:34:32.000Z")}
}
},
{"$group" : {"_id" : null,"count" : {"$sum" : 1}}},
{"$project" : {"_id" : 0}}
])
This is for Node js
var start = moment().startOf('day');
var end = moment().endOf('day');
history.aggregate([{
$addFields: {
convertedDate: { $toDate: "$date" }
}
},
{
"$match":
{
"convertedDate":
{
"$gte": start,
"$lte": end
}
}
},
{ "$group": { "_id": null, "count": { "$sum": 1 } } },
{ "$project": { "_id": 0 } }
], function (err, count) {
console.log(count)
})
Try:
history.count({date: {
$gte: start,
$lt: end
}}, function( err, count){
console.log( "Number of users:", count );
})
for native mongodb driver
db.collection(collectionName).count({}, function(error, numOfDocs){
if(error) return callback(error);
db.close();
callback(null, numOfDocs);
});
You are storing the string representation of the date. Try calling toDate() on moment object before storing into the database

Sub group Mongoose

I'm trying to get a sub gruop from a query using nodejs and mongoose.
The thing I'm trying to do is the following:
I have this collection:
I Need to count and group all the documents with the same 'intent' and make a subgroup with the 'entity' value, so far I have this running:
try {
//We first get the total interactions from all workspace
let workspace = await Interaction.aggregate([
{ $match: { dateAdded: { $gte: todayStart, $lt: todayEnd }, workspace: workspaceID } },
{ $group: { _id: "$workspace", data: { $sum: 1 } } },
{ $sort: { _id: 1 } }
]).exec();
//We then get the total results from conversations
let results = await Interaction.aggregate([
{ $match: { dateAdded: { $gte: todayStart, $lt: todayEnd }, workspace: workspaceID } },
{ $group: { _id: '$intent', data: { $sum: 1 } } },
{ $sort: { _id: 1 } }
]).exec()
//workspaceItems = workspace.map(function (Interaction) { return Interaction._id; });
return res.json({
total: workspace,
result: results
})
} catch (err) {
console.log(err);
return res.status(500).send(err)
}
The result look like this:
{
"total": [
{
"_id": "Business",
"data": 23
}
],
"result": [
{
"_id": "N/A",
"data": 2
},
{
"_id": "PRODUCTO_BENEFICIOS",
"data": 3
},
{
"_id": "PRODUCTO_DESCRIPCION",
"data": 10
},
{
"_id": "REPORTE_TARJETA_PERDIDA",
"data": 1
},
{
"_id": "REQUISITOS",
"data": 7
}
]
}
I need the result in this way :
{
"total": [
{
"_id": "Business",
"data": 23
}
],
"result": [
{
"_id": "N/A",
"data": 2
},
{
"_id": "PRODUCTO_BENEFICIOS",
"entities: [{"TARJETAS","PROMOCIONES"."ETC..."}],
"data": 3
},
{
"_id": "PRODUCTO_DESCRIPCION",
"entities: [{"TARJETAS","PROMOCIONES"."ETC..."}],
"data": 10
},
{
"_id": "REPORTE_TARJETA_PERDIDA",
"entities: [{"TARJETAS","PROMOCIONES"."ETC..."}],
"data": 1
},
{
"_id": "REQUISITOS",
"entities: [{"TARJETAS","PROMOCIONES"."ETC..."}],
"data": 7
}
]
}
I Hope to be clear, please let me know if you know how to do this using mongoose.
Thank you in advance.
try changing the 2nd query to following
let results = await Interaction.aggregate([
{ $match: { dateAdded: { $gte: todayStart, $lt: todayEnd }, workspace: workspaceID } },
{ $group: { _id: '$intent', entities: {$push: "$entity"}, data: { $sum: 1 } } },
{ $sort: { _id: 1 } }
]).exec()
if you want a unique list of entities you can use $addToSet instead of $push

Find element in array using mongodb

I simply want to count the element in array based on the query. I tried the following command but not solved my problem.
I want to count the element whose TimeStamp is in between "2017-02-17T18:30:00.000Z and "2017-02-18T18:29:59.999Z" on DATA2 array, but it returns only 1.
CODE Executed:
CODE 1
db.ABC.aggregate([{
$match: {
$and: [{
DATA2: {
$exists: true
}
}, {
"DATA2.TimeStamp": {
$gte: require('../../modules/getDates').getFromDate(item),
$lte: require('../../modules/getDates').getToDate(item)
}
}, {
Client_id: "123" /*req.query.client_id*/
}]
}
}, {
$project: {
DATASiz: {
$size: "$DATA2"
},
"has bananas": {
$in: ["DATA2.$.TimeStamp"]
}
}
}], function(err, result) {
console.log(result)
callBack();
})
Code 2
db.abc.find({ $and:[{DATA2: {$exists: true}},{Client_id: "123"},{"DATA2": { $elemMatch: { TimeStamp: { $gte: require('../../modules/getDates').getFromDate(item), $lte: require('../../modules/getDates').getToDate(item) } } }}]
}, function(err, result) {
console.log(JSON.stringify(result))
callBack();
})
Code 3
//db.abc.find //also tried
db.abc.count({
$and: [{
DATA2: {
$exists: true
}
}, {
"DATA2.TimeStamp": {
$gte: require('../../modules/getDates').getFromDate(item),
$lte: require('../../modules/getDates').getToDate(item)
}
}, {
Client_id: "123" /*req.query.client_id*/
}]
},{
"DATA2.$":1
}, function(err, result) {
console.log(result)
callBack();
})
JSON Format:
{
"_id": {
"$oid": "57c7404985737e2c78fde6b3"
},
"ABC": "1304258470",
"Status": "Not Found",
"DATA1": [
{123},{123},{123}
],
"Remark": "Not Found",
"DATA2": [
{
"TimeStamp": "2017-02-18T09:01:43.060Z",
"NdrStatus": "Door Locked",
},
{
"TimeStamp": "2017-02-18T08:09:43.347Z",
"NdrStatus": "HOLD",
},
{
"TimeStamp": "2017-02-20T08:09:43.347Z",
"NdrStatus": "HOLD",
}
]
}
Result:
I am getting the first element of DATA2 using CODE 3 but I know that as per the query 2 elements are to return.
I expect 2 as in count.
Also used $unwind $redact
Thanks in advance.
You can use the $filter and $size operators for this:
var start = require('../../modules/getDates').getFromDate(item),
end = require('../../modules/getDates').getToDate(item);
db.ABC.aggregate([
{
"$match": {
"DATA2": { "$exists": true },
"DATA2.TimeStamp": { "$gte": start, "$lte": end },
"Client_id": "123"
}
},
{
"$project": {
"DATASiz": {
"$size": {
"$filter": {
"input": "$DATA2",
"as": "item",
"cond": {
"$and": [
{ "$gte": ["$$item.TimeStamp", start] },
{ "$lte": ["$$item.TimeStamp", end] }
]
}
}
}
}
}
}
], function(err, result) {
console.log(result);
callBack();
});

Resources