I'm doing a small IoT project, and I want to show some useful informations that I get from the device.
The device is a switch button that controls one light bulb, each time the switch is activated, an event is sent to the database, here is two examples of the documents received:
{
"_id" : ObjectId("62baf5b98218da3bc80e9d61"),
"light_on" : false,
"device_id" : "ab082e4d-e617-4c74-8d41-fa316246afac",
"timestamp" : ISODate("2022-07-01T10:00:24.000 0000")
}
{
"_id" : ObjectId("62baf5b98218da3bc90e9d6a"),
"light_on" : true,
"device_id" : "ab082e4d-e617-4c74-8d41-fa316246afac",
"timestamp" : ISODate("2022-07-01T10:32:00.000 0000")
}
From this data, I want to extract:
- The mean duration of when the light was on
- The longest duration of the lights on
- Longest duration of lights off
- All duration that exceeded 4 hours of lightning on
This kind of request needs me to compare the documents two by two, which I never did in Mongo, and I'm not even sure it's doable, so any help is welcome.
CodePudding user response:
Try this one:
db.collection.aggregate([
{
$setWindowFields: {
partitionBy: "$device_id",
sortBy: { timestamp: 1 },
output: {
following: {
$shift: {
output: "$timestamp",
by: 1
}
}
}
}
},
{
$set: {
duration: {
$dateDiff: {
startDate: "$timestamp",
endDate: "$following",
unit: "second"
}
}
}
},
{
$facet: {
mean: [
{
$group: {
_id: {
device_id: "$device_id",
light_on: "$light_on"
},
mean: { $avg: "$duration" },
longest: { $max: "$duration" }
}
}
],
exceeded: [
{
$match: {
light_on: true,
duration: { $gt: 14400 } // 4 hours = 14400 seconds
}
}
]
}
}
])
For MongoDB version < 5.0 you need a different solution. As starting point is this one:
db.collection.aggregate([
{ $sort: { timestamp: -1 } },
{
$group: {
_id: "$device_id",
timestamp: { $push: "$$ROOT" }
}
},
{
$set: {
timestamp: {
$reduce: {
input: "$timestamp",
initialValue: [],
in: {
$concatArrays: [
"$$value",
[
{
$mergeObjects: [
"$$this",
{ following: { $last: "$$value.timestamp" },
duration: {
$dateDiff: {
endDate: { $last: "$$value.timestamp" },
startDate: "$$this.timestamp",
unit: "second"
}
}
}
]
}
]
]
}
}
}
}
},
... some cosmetic, see above
])