MongoDB - How to get last month records - mongodb

How can I fetch last month's records in MongoDB?
Following is the MYSQL query used to do the same:
SELECT * FROM table
WHERE YEAR(createdon) = YEAR(CURRENT_DATE - INTERVAL 1 MONTH)
AND MONTH(createdon) = MONTH(CURRENT_DATE - INTERVAL 1 MONTH)

Solution 1: $where operator for db.collection.find()
Supported version: Before 4.4
You can use $where which is supported with Javascript function().
db.collection.find({
$where: function() {
var currentDate = new Date();
var lastMonthDate = new Date(currentDate.setMonth(currentDate.getMonth() - 1));
return this.createdOn.getFullYear() === lastMonthDate.getFullYear()
&& this.createdOn.getMonth() === lastMonthDate.getMonth();
}
})
Note:
Wrap the function with the quotes in Mongo Playground is due to reported Github issue.
Sample Solution 1 on Mongo Playground
Solution 2: With $dateAdd for db.collection.aggregate()
Supported version: 5.0
With $dateAdd is introduced in version 5.0, you can perform the query as below:
$match:
With $match pipeline, using $expr query expression to include the aggregation operation.
$and operator to ensure both expressions are fulfilled.
Using $dateAdd operator to add month (unit) by -1 (amount) to get previous month date.
$month and $year are for getting the month and year value from date respectively.
And perform $eq operator to check both $month and $year from createdOn are matched with both $month and $year from previous month date respectively.
db.collection.aggregate([
{
$match: {
$expr: {
$and: [
{
"$eq": [
{
$month: "$createdOn"
},
{
$month: {
$dateAdd: {
startDate: new Date(),
unit: "month",
amount: -1
}
}
}
]
},
{
"$eq": [
{
$year: "$createdOn"
},
{
$year: {
$dateAdd: {
startDate: new Date(),
unit: "month",
amount: -1
}
}
}
]
}
]
}
}
}
])
Sample Solution 2 on Mongo Playground
Solution 3: With $dateFromParts for db.collection.aggregate()
Supported version: From 3.6
You may also apply with $dateFromParts which is suggested by this Jira comment.
db.collection.aggregate([
{
$match: {
$expr: {
$and: [
{
"$eq": [
{
$month: "$createdOn"
},
{
$month: {
$let: {
"vars": {
"todayDate": new Date()
},
"in": {
$dateFromParts: {
year: {
$year: "$$todayDate"
},
month: {
$subtract: [
{
$month: "$$todayDate"
},
1
]
},
day: {
$dayOfMonth: "$$todayDate"
}
}
}
}
}
}
]
},
{
"$eq": [
{
$year: "$createdOn"
},
{
$year: {
$let: {
"vars": {
"todayDate": new Date()
},
"in": {
$dateFromParts: {
year: {
$year: "$$todayDate"
},
month: {
$subtract: [
{
$month: "$$todayDate"
},
1
]
},
day: {
$dayOfMonth: "$$todayDate"
}
}
}
}
}
}
]
}
]
}
}
}
])
Sample Solution 3 on Mongo Playground

You can select the records between two dates using the $gte and $lte options. Example:
db.getCollection('your-collection-name').find({
{createdAt:{$gte:ISODate(“2020-03-01”),$lt:ISODate(“2021-03-31”)}}
})
more information about these operators:
$lte -> https://docs.mongodb.com/manual/reference/operator/query/lte/
$gte -> https://docs.mongodb.com/manual/reference/operator/query/gte/

Related

How to get the results from the last x days/months/years in MongoDB

I am trying to get a set of results in MongoDB (version 4.2) using only MongoDB Query Language where a specific date is greater than 30 days before today (that is, I need the data from the last 30 days, starting at 00:00h of the day 30 days ago).
I have tried this, but it does not yield any results:
{
date: {
$gte: {
$dateFromParts: {
year: {
$year: new Date()
},
month: {
$month: new Date()
},
day: {
$add: [
{$dayOfMonth: new Date()},
-30
]
}
}
}
}
}
Obviously, I checked that there were results when I entered the date directly this way (being today the 13th of December of 2022):
{date: {$gte: ISODate('2022-11-13')}}
Thank you for the help!
UPDATE 1:
Thanks to #wernfried-domscheit, I came to this solution, although it is very slow. If there was a solution that does not involve using $expr...
{
$expr: {
$gte: [
"$date",
{
$dateFromParts: {
year: {
$year: new Date()
},
month: {
$month: new Date()
},
day: {
$add: [
{
$dayOfMonth: Date()
},
-30
]
}
}
}
]
}
}
Try this one:
db.collection.find({
$expr: {
$gt: [
"$date",
{
$dateSubtract: {
startDate: { $dateTrunc: { date: ISODate(), unit: "day" } },
unit: "day",
amount: 30
}
}
]
}
})
For older version of MongoDB, use
db.collection.find({
$expr: {
$gt: [
"$date",
{
$subtract: [
{
$dateFromParts: {
year: { $year: ISODate() },
month: { $month: ISODate() },
day: { dayOfMonth: ISODate() }
}
},
1000 * 60 * 60 * 24 * 30
]
}
]
}
})

how to obtain the days where the sum of the values is greater than 420 in mongo

I'm trying to sum the 'emsion_co2' values by day. in order to know in what days the value is higher than 420, but my query is not working.
this is the database
db.test_sensores.insert([{"timestamp":"2020-07-01T00:00:00Z","dia":01,"sensor_id":1,"location_id":1,"medidas":[{"tipo_medida":"Temperatura","valor":16.61,"unidad":"ºC"},{"tipo_medida":"Humedad_relativa","valor":83.74,"unidad":"%"}]},
{"timestamp":"2020-07-01T00:00:00Z","dia":01,"sensor_id":2,"location_id":1,"medidas":[{"tipo_medida":"Emision_CO2","valor":1.572,"unidad":"gCO2/m2"},{"tipo_medida":"Consumo_electrico","valor":0.00188,"unidad":"kWh/m2"}]},
{"timestamp":"2020-07-01T00:15:00Z","dia":01,"sensor_id":1,"location_id":1,"medidas":[{"tipo_medida":"Temperatura","valor":15.75,"unidad":"ºC"},{"tipo_medida":"Humedad_relativa","valor":83.08,"unidad":"%"}]},
{"timestamp":"2020-07-01T00:15:00Z","dia":01,"sensor_id":2,"location_id":1,"medidas":[{"tipo_medida":"Emision_CO2","valor":1.626,"unidad":"gCO2/m2"},{"tipo_medida":"Consumo_electrico","valor":0.00146,"unidad":"kWh/m2"}]},
{"timestamp":"2020-07-10T00:30:00Z","dia":10,"sensor_id":1,"location_id":1,"medidas":[{"tipo_medida":"Temperatura","valor":14.08,"unidad":"ºC"},{"tipo_medida":"Humedad_relativa","valor":90.05,"unidad":"%"}]},
{"timestamp":"2020-07-10T00:30:00Z","dia":10,"sensor_id":2,"location_id":1,"medidas":[{"tipo_medida":"Emision_CO2","valor":1.614,"unidad":"gCO2/m2"},{"tipo_medida":"Consumo_electrico","valor":0.00173,"unidad":"kWh/m2"}]},
{"timestamp":"2020-07-01T00:45:00Z","dia":01,"sensor_id":1,"location_id":1,"medidas":[{"tipo_medida":"Temperatura","valor":10.62,"unidad":"ºC"},{"tipo_medida":"Humedad_relativa","valor":92.27,"unidad":"%"}]},
{"timestamp":"2020-07-01T00:45:00Z","dia":01,"sensor_id":2,"location_id":1,"medidas":[{"tipo_medida":"Emision_CO2","valor":1.59,"unidad":"gCO2/m2"},{"tipo_medida":"Consumo_electrico","valor":0.00196,"unidad":"kWh/m2"}]},
{"timestamp":"2020-07-01T00:00:00Z","dia":01,"sensor_id":1,"location_id":2,"medidas":[{"tipo_medida":"Temperatura","valor":22.08,"unidad":"ºC"},{"tipo_medida":"Humedad_relativa","valor":34.92,"unidad":"%"}]},
{"timestamp":"2020-07-01T00:00:00Z","dia":01,"sensor_id":2,"location_id":2,"medidas":[{"tipo_medida":"Emision_CO2","valor":2.055,"unidad":"gCO2/m2"},{"tipo_medida":"Consumo_electrico","valor":0.00269,"unidad":"kWh/m2"}]},
{"timestamp":"2020-07-01T00:15:00Z","dia":01,"sensor_id":1,"location_id":2,"medidas":[{"tipo_medida":"Temperatura","valor":21.12,"unidad":"ºC"},{"tipo_medida":"Humedad_relativa","valor":37.7,"unidad":"%"}]},
{"timestamp":"2020-07-01T00:15:00Z","dia":01,"sensor_id":2,"location_id":2,"medidas":[{"tipo_medida":"Emision_CO2","valor":2.102,"unidad":"gCO2/m2"},{"tipo_medida":"Consumo_electrico","valor":0.00272,"unidad":"kWh/m2"}]},
{"timestamp":"2020-07-10T00:30:00Z","dia":10,"sensor_id":1,"location_id":2,"medidas":[{"tipo_medida":"Temperatura","valor":24.26,"unidad":"ºC"},{"tipo_medida":"Humedad_relativa","valor":52.52,"unidad":"%"}]},
{"timestamp":"2020-07-10T00:30:00Z","dia":10,"sensor_id":2,"location_id":2,"medidas":[{"tipo_medida":"Emision_CO2","valor":2.023,"unidad":"gCO2/m2"},{"tipo_medida":"Consumo_electrico","valor":0.00255,"unidad":"kWh/m2"}]},
{"timestamp":"2020-07-01T00:45:00Z","dia":01,"sensor_id":1,"location_id":2,"medidas":[{"tipo_medida":"Temperatura","valor":24.51,"unidad":"ºC"},{"tipo_medida":"Humedad_relativa","valor":34.1,"unidad":"%"}]},
{"timestamp":"2020-07-01T00:45:00Z","dia":01,"sensor_id":2,"location_id":2,"medidas":[{"tipo_medida":"Emision_CO2","valor":1.957,"unidad":"gCO2/m2"},{"tipo_medida":"Consumo_electrico","valor":0.00215,"unidad":"kWh/m2"}]}])
And the next query is what I was trying, but the result is wrong because there is not showing the sum, just appear in 0 the values.
db.test_sensores.aggregate([{$match:{'medidas.tipo_medida':'Emision_CO2'}},{$group:{_id:'$dia', acumulado_emisiones_CO2:{$sum:'$medidas.0.valor'}}}])
In my query is missing how to find the days where emision_co2 value > 420 too, I was thinking manually but if there is an automated way, please let me know. Thank you
Unsure why you attempt to group by dia,
$match
$set - Set timestamp to Date object, medidas_Emision_CO2_valor for sum all the values in medidas array by filtering ($filter) the document with tipo_medida is "Emision_CO2" via $reduce.
$group - Group by date, month, and year of timestamp and sum the medidas_Emision_CO2_valor values as acumulado_emisiones_CO2.
$match - Filter the documents with acumulado_emisiones_CO2 is greater than ($gt) 420.
db.test_sensores.aggregate([
{
$match: {
"medidas.tipo_medida": "Emision_CO2"
}
},
{
$set: {
timestamp: {
$toDate: "$timestamp"
},
medidas_Emision_CO2_valor: {
$reduce: {
input: {
$filter: {
input: "$medidas",
cond: {
$eq: [
"$$this.tipo_medida",
"Emision_CO2"
]
}
}
},
initialValue: 0,
in: {
$sum: [
"$$value",
"$$this.valor"
]
}
}
}
}
},
{
$group: {
_id: {
day: {
"$dayOfMonth": "$timestamp"
},
month: {
"$month": "$timestamp"
},
year: {
$year: "$timestamp"
}
},
acumulado_emisiones_CO2: {
$sum: "$medidas_Emision_CO2_valor"
}
}
},
{
$match: {
"acumulado_emisiones_CO2_valor": {
$gt: 420
}
}
}
])
Sample Mongo Playground

Group documents with MongoDB

I come from the world of relational databases and am having difficulty with a MongoDB query.
In my database I have telemetry documents with minute-by-minute records for each monitored system.
I'm tending to do a query that groups records by hour.
Below is a demonstration of the structure of my documents:
{
_id: ObjectId("61847b83618fc8a6fb368ab7"),
system_code: 22,
date: ISODate("2021-08-01T00:00:01.000Z"),
value1: 22.2372973251,
value2: 20
}
Here's the structure of the query I'm trying to run:
db.telemetry.aggregate([
{
$match: {
$and: [
{ system_code: 22 },
{ date: { $gte: ISODate("2021-08-01 00:00:00") } },
{ date: { $lte: ISODate("2021-08-01 02:00:00") } }
]
}
},
{
$addFields: {
italianDate: {
$dateToString: {
format: "%d/%m/%Y %H:00:00",
date: "$date"
}
}
}
},
{
$sort: {
italianDate: 1
}
},
{
$group: {
_id: {
year: { $year: "$date" },
month: { $month: "$date" },
day: { $dayOfMonth: "$date" },
hour: { $hour: "$date" }
}
}
}
]);
The SQL query with PostgreSQL is exactly this:
SELECT TO_CHAR(t.date, 'YYYY-MM-DD HH24:00:00') AS italianDate, AVG(value1), AVG(value2) FROM telemetry t WHERE t.system_code = 22 AND t.date BETWEEN '2021-08-01 00:00:00' AND '2021-08-01 02:00:00' GROUP BY italianDate ORDER BY italianDate ASC
Thank you so much if you can help me.
You are actually pretty close. You just need to put the $avg inside your $group stage. Another thing is you need to pay attention to the date formats. Refer to this official MongoDB document for the formats.
db.telemetry.aggregate([
{
$match: {
system_code: 22,
date: {
$gte: ISODate("2021-08-01T00:00:00Z"),
$lte: ISODate("2021-08-01T02:00:00Z")
}
}
},
{
$addFields: {
italianDate: {
$dateToString: {
format: "%Y-%m-%d %H:00:00",
date: "$date"
}
}
}
},
{
$group: {
_id: "$italianDate",
avgValue1: {
$avg: "$value1"
},
avgValue2: {
$avg: "$value2"
}
}
},
{
$sort: {
_id: -1
}
}
])
Here is the Mongo playground for your reference.

MongoDB aggregation add months or years to a Date

We can use $add to add Dates in the aggregation pipe. Is there a way to add a specific number of time units (ie days months or years) except milliseconds?
The current way to add 3 years is date: { $add: [ "$date", 3*365*24*60*60000 ] }
My expected syntax format is date: { $add: [ "$date", { $years:3 } ] } which is not working
As mentioned in my comment, you will get this function Mongo 5.0
In the meantime you can use this workaround:
db.collection.aggregate([
{
$addFields: {
new_date: {
$dateFromParts: {
year: { $add: [{ $year: "$date" }, 3] },
month: { $month: "$date" },
day: { $dayOfMonth: "$date" },
hour: { $hour: "$date" },
minute: { $minute: "$date" },
second: { $second: "$date" },
millisecond: { $millisecond: "$date" }
}
}
}
}
])

Mongo query: compare multiple of the same field (timestamps) to only show documents that have a few second difference

I am spinning my wheels on this. I am needing to find all documents within a collection that have a timestamp ("createdTs") that have a 3 second or less difference (to be clear: month/day/time/year all the same, save those few seconds). An example of createdTs field (it's type Date): 2021-04-26T20:39:01.851Z
db.getCollection("CollectionName").aggregate([
{ $match: { memberId: ObjectId("1234") } },
{
$project:
{
year: { $year: "$createdTs" },
month: { $month: "$createdTs" },
day: { $dayOfMonth: "$createdTs" },
hour: { $hour: "$createdTs" },
minutes: { $minute: "$createdTs" },
seconds: { $second: "$createdTs" },
milliseconds: { $millisecond: "$createdTs" },
dayOfYear: { $dayOfYear: "$createdTs" },
dayOfWeek: { $dayOfWeek: "$createdTs" },
week: { $week: "$createdTs" }
}
}
])
I've tried a lot of different variances. Where I'm struggling is how to compare these findings to one another. I'd also prefer to just search the entire collection and not match on the "memberId" field, just collect any documents that have less than a 3 second createdTs difference, and group/display those.
Is this possible? Newer to Mongo, and spun my wheels on this for two days now. Any advice would be greatly appreciated, thank you!
I saw this on another post, but not sure how to utilize it since I'm wanting to compare the same field:
db.collection.aggregate([
{ "$project": {
"difference": {
"$divide": [
{ "$subtract": ["$logoutTime", "$loginTime"] },
60 * 1000 * 60
]
}
}},
{ "$group": {
"_id": "$studentID",
"totalDifference": { "$sum": "$difference" }
}},
{ "$match": { "totalDifference": { "$gte": 20 }}}
])
Also am trying...
db.getCollection("CollectionName").aggregate([
{ $match: { memberId: ObjectId("1234") } },
{
$project:
{
year: { $year: "$createdTs" },
month: { $month: "$createdTs" },
total:
{ $add: ["$year", "$month"] }
}
}
])
But this returns a total of null. Not sure if it's because $year and $month are difference? The types are both int32, so I thought that'd work. Was wondering if there's a way to compare if all the fields are 0, then if seconds is not/difference is $gte 3 when using $group, could go from there.