Агрегация в mongodb и группе по 15 мин. - PullRequest
0 голосов
/ 11 января 2020

У меня есть схема в mongodb, например: INPUT

{
  _id: ObjectId("5e05c1089b3e4e333cee8c39"),
  name:"Alex",
  activity:[
        {
            _id: ObjectId("5e05c1089b3e4e333cee8c39"),
            type: 'run',
            start_timestamp: ISODate("2020-01-11T11:34:59.804Z"),
            end_timestamp: ISODate("2020-01-11T11:40:00.804Z")
        },
        {
            _id: ObjectId("5e05c1089b3e4e333cee8c40"),
            type: 'stop',
            start_timestamp: ISODate("2020-01-11T11:40:00.804Z"),
            end_timestamp: ISODate("2020-01-11T11:42:00.804Z")
        },
        {
            _id: ObjectId("5e05c1089b3e4e333cee8c41"),
            type: 'wait',
            start_timestamp: ISODate("2020-01-11T11:42:00.804Z"),
            end_timestamp: ISODate("2020-01-11T11:52:00.804Z")
        },
        {
            _id: ObjectId("5e05c1089b3e4e333cee8c41"),
            type: 'stop',
            start_timestamp: ISODate("2020-01-11T11:52:00.804Z"),
            end_timestamp: ISODate("2020-01-11T12:02:00.804Z")
        },
        {
            _id: ObjectId("5e05c1089b3e4e333cee8c41"),
            type: 'sleep',
            start_timestamp: ISODate("2020-01-11T12:02:00.804Z"),
            end_timestamp: ISODate("2020-01-11T12:48:00.804Z")
        }
  ]
}

Это схема для деятельности человека, мне нужно находить торможение каждые 15 минут (длительность торможения в минутах), Я нашел решение StackOverflow, но здесь только одна временная метка, но в моем случае есть 2 временные метки, и сначала я должен рассчитать продолжительность, а затем сгруппировать по 15 минутам

OUTPUT

[
  {
        _id: "2020-01-11T11:34 to 2020-01-11T11:49" ,
        duration: "15 min",
        "brake-up":{
          run:"6 min",
          stop:"2 min",
          wait:"7 min"
        }
   },
   {
        _id: "2020-01-11T11:49 to 2020-01-11T12:04" , 
        duration: 15 min,
        "brake-up":{
          wait:"3 min"
          stop:"10 min"
          sleep:"2 min"
        }
   {
        _id: "2020-01-11T12:04 to 2020-01-11T12:19" , 
        duration: 15 min,
        "brake-up":{
          sleep:"15 min"
        }
   }
]

Спасибо

1 Ответ

1 голос
/ 11 января 2020

Это немного утомительное решение.

Пояснение

Я предполагаю, activity.type не повторяется внутри X мин распада Я предполагаю start_timestamp и end_timestamp as is (не игнорируйте секунды: миллисекунды)

  1. Мы рассчитываем минимальные / максимальные даты из start_timestamp и end_timestamp
  2. Мы вычисляем, сколько 15 min breaks находится между минимальными / максимальными датами
  3. Мы создаем from и to переменных, которые включают X минимальный разбив по минимальным / максимальным датам
  4. Для каждый from и to, мы фильтруем действия
  5. . После фильтрации мы рассчитываем потерянное время, учитывая from и to и start_timestamp и end_timestamp даты

db.collection.aggregate([
  {
    $project: {
      root: "$$ROOT",
      duration: {
        $toInt: 15
      },
      "start": {
        $reduce: {
          "input": "$activity",
          initialValue: ISODate("2100-01-01"),
          in: {
            $min: [
              "$$value",
              "$$this.start_timestamp",
              "$$this.end_timestamp"
            ]
          }
        }
      },
      "end": {
        $reduce: {
          "input": "$activity",
          initialValue: ISODate("1970-01-01"),
          in: {
            $max: [
              "$$value",
              "$$this.start_timestamp",
              "$$this.end_timestamp"
            ]
          }
        }
      }
    }
  },
  {
    $addFields: {
      interval: {
        $range: [
          0,
          {
            $round: {
              $divide: [
                {
                  $toLong: {
                    $subtract: [
                      "$end",
                      "$start"
                    ]
                  }
                },
                {
                  $multiply: [
                    "$duration",
                    60,
                    1000
                  ]
                }
              ]
            }
          },
          1
        ]
      }
    }
  },
  {
    $unwind: "$interval"
  },
  {
    $addFields: {
      from: {
        $add: [
          "$start",
          {
            $multiply: [
              "$interval",
              {
                $multiply: [
                  "$duration",
                  60,
                  1000
                ]
              }
            ]
          }
        ]
      },
      to: {
        $min: [
          "$end",
          {
            $add: [
              "$start",
              {
                $multiply: [
                  {
                    $add: [
                      "$interval",
                      1
                    ]
                  },
                  {
                    $multiply: [
                      "$duration",
                      60,
                      1000
                    ]
                  }
                ]
              }
            ]
          }
        ]
      },
      activity: "$root.activity"
    }
  },
  {
    $addFields: {
      activity: {
        $filter: {
          input: "$activity",
          cond: {
            $or: [
              {
                $and: [
                  {
                    $gte: [
                      "$$this.start_timestamp",
                      "$from"
                    ]
                  },
                  {
                    $lte: [
                      "$$this.end_timestamp",
                      "$to"
                    ]
                  }
                ]
              },
              {
                $and: [
                  {
                    $lte: [
                      "$$this.start_timestamp",
                      "$to"
                    ]
                  },
                  {
                    $gte: [
                      "$$this.end_timestamp",
                      "$from"
                    ]
                  }
                ]
              }
            ]
          }
        }
      }
    }
  },
  {
    $project: {
      _id: {
        $concat: [
          {
            $toString: "$from"
          },
          " to ",
          {
            $toString: "$to"
          }
        ]
      },
      name: "$root.name",
      duration: {
        $concat: [
          {
            $toString: "$duration"
          },
          " min"
        ]
      },
      "brake-up": {
        $map: {
          input: "$activity",
          in: {
            k: "$$this.type",
            v: {
              $round: {
                $divide: [
                  {
                    "$subtract": [
                      {
                        $min: [
                          "$$this.end_timestamp",
                          "$to"
                        ]
                      },
                      {
                        $max: [
                          "$$this.start_timestamp",
                          "$from"
                        ]
                      }
                    ]
                  },
                  {
                    $multiply: [
                      60,
                      1000
                    ]
                  }
                ]
              }
            }
          }
        }
      }
    }
  },
  {
    $unwind: "$brake-up"
  },
  {
    $group: {
      _id: {
        _id: "$_id",
        duration: "$duration",
        name: "$name",
        "brake-up-k": "$brake-up.k"
      },
      "brake-up-v": {
        $sum: "$brake-up.v"
      }
    }
  },
  {
    $group: {
      _id: {
        _id: "$_id._id",
        duration: "$_id.duration",
        name: "$_id.name"
      },
      "brake-up": {
        $push: {
          k: "$_id.brake-up-k",
          v: {
            $concat: [
              {
                $toString: "$brake-up-v"
              },
              " min"
            ]
          }
        }
      }
    }
  },
  {
    $project: {
      _id: "$_id._id",
      name: "$_id.name",
      duration: "$_id.duration",
      "brake-up": {
        $arrayToObject: "$brake-up"
      }
    }
  },
  {
    $sort: {
      _id: 1
    }
  }
])

MongoPlayground

...