Find upcoming birthday from the array of date - mongodb

I have array of dates childrendob like
[
"2000-01-21T15:18:49+05:30",
"2008-03-12T15:18:49+05:30"
]
I want to fetch data from users table in which the children birthday is after 7 days from today.
Like suppose today is 15 Jan and result should be all users for which childrendob is 21-1
I need mongodb query for this

Get month and day after 7 days from your client side,
let date = new Date();
date.setDate(date.getDate() + 7); // add 7 days in current date
let month = date.getMonth() + 1; // month
let day = date.getDate(); // date
$filter to iterate loop of dates array, check $and condition from month and day,
$toDate to convert string date to ISO date, it its already in ISO date then you can skip/remove this conversation
$month to get month from date
$dayOfMonth to get date form date
$match for dates should not be empty
db.collection.aggregate([
{
$project: {
dates: {
$filter: {
input: "$dates",
cond: {
$and: [
{ $eq: [{ $month: { $toDate: "$$this" } }, month] }, // input month variable
{ $eq: [{ $dayOfMonth: { $toDate: "$$this" } }, day] } // input day variable
]
}
}
}
}
},
{ $match: { dates: { $ne: [] } } }
])
Playground

Related

mongodb find oldest date of three keys in each document

I have a document schema that looks like this:
{
status: String,
estimateDate: Date,
lostDate: Date,
soldDate: Date,
assignedDate: Date
}
With this schema all three dates could exists and none of them could exists. I need to do a check of all three and if at least one exists use the oldest date if none exists use todays date. With the "returned" date, get the difference in days from another key (assignedDate). I have figured out how to do what I want with one date but cannot figure out how to scale this up to include all three keys. Below is the working code I have for one key.
Within my aggregate pipeline $project stage I do the following:
days: {
$cond: {
if: {
$not: ["$date1"]
},
then: {
$floor: {
$divide: [
{
$subtract: [new Date(), "$assignedDate"]
},
1000 * 60 * 60 * 24
]
}
},
else: {
$floor: {
$divide: [
{
$subtract: [
"$estimateDate",
"$assignedDate"
]
},
1000 * 60 * 60 * 24
]
}
}
}
}
You can use $min and $ifNull operators to get oldest date specify new Date() as default value if any of those dates does not exist:
db.col.aggregate([
{
$project: {
oldest: {
$min: [
{ $ifNull: [ "$lostDate", new Date() ] },
{ $ifNull: [ "$soldDate", new Date() ] },
{ $ifNull: [ "$assignedDate", new Date() ] },
]
}
}
}
])

mongodb - $dateFromString to support multiple format

I have a string field in mongodb which should be converted to a date field.
The format of the string is like the following:
2014 - Only year, default month and day are 01 and 01, so it should be converted to date '2014-01-01'
2014-01 - With year and month, which should also be converted to date '2014-01-01'
2014-01-01 - Full date
$dateFromString in the following syntax doesn't seem to work:
$dateFromString: {
dateString: '$order.date',
format: '%Y-%m-%d',
}
How can I make $dateFromString to support multiple format?
What you could do is to add a new field via $addFields and then for its value create few if conditions using the $cond pipeline operator matching each of your date lengths (via $strLenCP) and concatenating the remaining parts (via $concat). Then since all of your date fields will now match the format %Y-%m-%d it should work ... like this:
db.getCollection('<YourCol>').aggregate([{
$addFields: {
dateFixed: {
$cond: {
if: { $eq: [{ $strLenCP: "$date"}, 4] }, // <-- "2011"
then: { $concat: ["$date", "-01-01"] },
else: {
$cond: {
if: { $eq: [{ $strLenCP: "$date" }, 7] }, // <-- "2011-01"
then: { $concat: ["$date", "-01"] },
else: "$date" // <-- "2011-01-01"
}
}
}
}
}
},
{
$project: {
date: {
$dateFromString: {
dateString: 'dateFixed',
format: '%Y-%m-%d'
}
}
}
}
])
You can see it working here

mongodb find between dates (month, year)

I have a collection with two fields, similar to the one bellow:
{
year: 2017,
month: 04 }
How can i select documents between 2017/07 - 2018/04?
Solved with:
db.collection.aggregate(
// Pipeline
[
// Stage 1
{
$addFields: {
"date": {
"$dateFromParts": {
"year": "$year",
"month": {"$toInt": "$month"}
}
}
}
},
// Stage 2
{
$match: {
"date": {
"$gte": ISODate("2017-07-01T00:00:00.000Z"),
"$lte": ISODate("2018-04-30T00:00:00.000Z")
}
}
},
]
);
Firstly you have to make sure you db is storing date in ISO format ( a format that mongo supports )
You can use following command to find documents :-
model.find({
date:{
$gte:ISODate("2017-04-29T00:00:00.000Z"),
$lte:ISODate("2017-07-29T00:00:00.000Z"),
}
})
Where model is the name of the collection and date is a attribute of
document holding dates in ISO format.

how to get last day of current month in mongo

I have following code:
var l_date = new Date();
l_date.setDate(30);
l_date.setHours(23);
l_date.setMinutes(59);
l_date.setSeconds(59);
l_date;
but I want programmatically to set last day of month since it is not constant by using a function to retrieve this data, how to get that in mongo???
var userMonth = 0; // January
var userYear = 2016
var d = new Date(userYear, userMonth + 1, 0);
d -> Last day of the userMonth
Trying to achieve the Last day of the month via Javascript
For MongoDb
var dayNo = 3
var answer = new Date(ISODate().getTime() + 1000 * 3600 * 24 * dayNo )
Here answer will be the third day from Current Date.
If anyone want to calculate this using aggregation, then this can help.
In MongoDB 4.2, was include $$NOW, a variable that can be accessed in aggregation pipelines which returns the current time as an ISODate.
db.collection.aggregate([
{
"$project": {
monthEnd: {
$subtract: [
{
$dateFromParts: {
"year": {
$year: "$$NOW"
},
"month": {
$add: [
{
$month: "$$NOW"
},
1
]
}
}
},
86400000
]
}
}
}
])
As this answer is being created in July of 2020, then the result is:
[
{
"_id": ObjectId("5a934e000102030405000000"),
"monthEnd": ISODate("2020-07-31T00:00:00Z")
}
]
var d= new Date(this.getFullYear(), this.getMonth()+1, 0);
return d.getDate();
JavaScript code to get number of days in month that will be last day of month

MongoDB aggregation : time series with granularity

I have a MongoDB Analytics-style collection. It contains documents with a timestamp field and various data. Now I want to get a time series with the number of documents for a time period with a granularity parameter.
I'm currently using the aggregation framework like this (assuming that the granularity is DAY) :
db.collection.aggregate([{
$match: {
timestamp: {
$gte: start_time,
$lt: end_time
}
}
}, {
$group: {
_id: {
year: { $year: '$timestamp' },
month: { $month: '$timestamp' },
day: { $dayOfMonth: '$timestamp' }
},
count: { $sum: 1 }
}
}, {
$sort: {
_id: 1
}
}])
This way I have a count value for every day.
The problem is that the counts will depend on the timezone used when computing the $dayOfMonth part (each count is from 00:00:000 UTC to 23:59:999 UTC).
I would like to be able to achieve this without being dependant on the timezone, but relying on the start_time.
For example, if I use a start_time at 07:00 UTC, I will get counts for every day at 07:00 UTC to the next day at 07:00 UTC.
TL;DR : I want something like this : https://dev.twitter.com/ads/reference/get/stats/accounts/%3Aaccount_id/campaigns
Any idea on how to perform this ?
I found a solution that works pretty good. It's not very natural but anyway.
The idea is to compute a "normalized" date based on the startDate and the date of the row. I use the $mod operator on the startDate to get the milliseconds + seconds + hours (in the case of a DAY granularity), and then I use $subtract to subtract it from the date of the row.
Here is an example for a DAY granularity :
var startDate = ISODate("2015-08-25 13:30:00.000Z")
var endDate = ISODate("2015-08-27 13:30:00.000Z")
db.collection.aggregate([{
$match: {
timestamp: {
$gte: startDate,
$lt: endDate
}
}, {
$project: {
timestamp_normalized: {
$subtract: [
"$timestamp",
{
$mod: [
{ "$subtract": [ startDate, new Date("1970-01-01") ] },
1000 * 60 * 60 * 24
]
}
]
}
}
}, {
// now $group with $dayOfMonth
}])
The $mod part computes the hours + seconds + milliseconds of the startDate after 00:00 UTC, in milliseconds.
The $subtract retrieves these milliseconds from the original timestamp.
Now I can use $dayOfMonth operator on my normalized_timestamp field to get the day if we consider intervals from 13:30 to 13:30 the next day, and use $group to get count values for these intervals.
EDIT: It's even easier to compute the value to remove from the timestamp for normalization before creating the query, using :
(startDate - new Date(0)) % (1000 * 60 * 60 * 24)
(for a DAY granularity)
Then subtract directly this value from timestamp instead of using $mod.