Разница во времени запроса сложного временного ряда по типу действия - PullRequest
0 голосов
/ 21 ноября 2018

У меня есть такая структура данных документов в MongoDB, и она предназначена для комплексного анализа данных с любой точки зрения относительно временных рядов различных действий (плоский журнал данных).Мне было трудно извлечь время, затрачиваемое между изменениями определенного типа на документ, используя монго-запросы, а затем применяя функцию $graphLookup (показано ниже).Я новичок в MongoDB, и мне нужна помощь с запросом для извлечения необходимых данных.

структура данных одного документа (пример):

{  
    "_id":NumberInt(1),
    "Creation":     ISODate("2018-11-19T06:30:42Z"),
    "Creator":      NumberInt(1),
    "Replies":      NumberInt(10),
    //... other aggregated properties 
    "CurrentProperties":{  // a copy of the last update signifying the current state
        "StatusId":         NumberInt(8),
        "PriorityId":       NumberInt(6),
        "DepartmentId":     NumberInt(5),
        "TypeId":           NumberInt(4),
        "CategoryId":       NumberInt(2),
        "SubcategoryId":    NumberInt(333),
        "ChangeTime":       ISODate("2018-11-19T10:17:20Z"),
        "TimeDelta":        NumberLong(3600000), //timespan from last change in MS 
        "ChangeType":       NumberInt(4),
        "UserId":           NumberInt(1)
    },
    "ChangeHistory":[  // time series changes
        {  
            "StatusId":         NumberInt(8),
            "PriorityId":       NumberInt(6),
            "DepartmentId":     NumberInt(1),
            "TypeId":           NumberInt(4),
            "CategoryId":       NumberInt(2),
            "SubcategoryId":    NumberInt(333),
            "ChangeTime":       ISODate("2018-11-19T10:14:20Z"),
            "TimeDelta":        NumberLong(0), //timespan from last change in MS 
            "ChangeType":       NumberInt(0), // the changed property identifier (0= creation)
            "UserId":           NumberInt(1)
        },
        {  
            "StatusId":         NumberInt(8),
            "PriorityId":       NumberInt(6),
            "DepartmentId":     NumberInt(2),
            "TypeId":           NumberInt(4),
            "CategoryId":       NumberInt(2),
            "SubcategoryId":    NumberInt(333),
            "ChangeTime":       ISODate("2018-11-19T10:15:50Z"),
            "TimeDelta":        NumberLong(90000), //timespan from last change in MS 
            "ChangeType":       NumberInt(4), // the changed property identifier (4= department)
            "UserId":           NumberInt(1)
        },
        {  
            "StatusId":         NumberInt(2),
            "PriorityId":       NumberInt(6),
            "DepartmentId":     NumberInt(2),
            "TypeId":           NumberInt(4),
            "CategoryId":       NumberInt(2),
            "SubcategoryId":    NumberInt(333),
            "ChangeTime":       ISODate("2018-11-19T10:16:20Z"),
            "TimeDelta":        NumberLong(30000), //timespan from last change in MS 
            "ChangeType":       NumberInt(2), // the changed property identifier (2= status)
            "UserId":           NumberInt(1)
        },
        {  
            "StatusId":         NumberInt(2),
            "PriorityId":       NumberInt(6),
            "DepartmentId":     NumberInt(5),
            "TypeId":           NumberInt(4),
            "CategoryId":       NumberInt(2),
            "SubcategoryId":    NumberInt(333),
            "ChangeTime":       ISODate("2018-11-19T10:17:20Z"),
            "TimeDelta":        NumberLong(60000), //timespan from last change in MS 
            "ChangeType":       NumberInt(4), // the changed property identifier (4= department)
            "UserId":           NumberInt(1)
        }
    ]
}

Ожидаемый результат дляизменения отдела во времени:

[{
    RecordID:       1,
    Department:     1,
    ChangeTime:     ISODate("2018-11-19T10:15:50Z"),
    TimeSpent:      90000
},
{
    RecordID:       1,
    Department:     2,
    ChangeTime:     ISODate("2018-11-19T10:17:20Z")
    TimeSpent:      90000
},
{
    RecordID:       1,
    Department:     5,
    ChangeTime:     ISODate("2018-11-21T09:47:47Z") // Current Time
    TimeSpent:      171027000 //difference between now and last change in departments
}]

и для статуса:

[{
    RecordID:       1,
    Status:         8,
    ChangeTime:     ISODate("2018-11-19T10:16:20Z"),
    TimeDelta:      120000
},
{
    RecordID:       1,
    Status:         2,
    ChangeTime:     ISODate("2018-11-21T09:47:47Z"), // Current Time
    TimeDelta:      171087000 //difference between now and last change in status
}]

Что я пробовал до сих пор

Лучший результат, который я получил, такfar использовал следующую агрегацию для создания представления, а затем применил к представлению функцию $GraphLookup:

db.test.aggregate([
    {$project: {
      _id:0,
      RecordID: "$_id",
      history: {
        $filter: {
          input: "$ChangeHistory",
          as: "changeHistory",
          cond: {$or:[
            {$eq:["$$changeHistory.ChangeType",0]},
            {$eq:["$$changeHistory.ChangeType",4]}
            ]}

                }
      }
    }}, 
    {$unwind: {
      path: "$history",
      includeArrayIndex:"order"
    }}, {$project: {
      _id:"$RecordID",
      "RecordID": "$RecordID",
      "departmentID": "$history.DepartmentId",
      "actionOrder":"$order",
      "nextAction":{$add:["$order",1]},
      "time":"$history.ChangeTime"
    }}
])

, а затем применил следующее:

db.TestView.aggregate([{
        $graphLookup: {
            from: 'TestView',
            startWith: "$nextAction",
            connectFromField: 'nextAction',
            connectToField: 'actionOrder',
            as: 'pair',
        }
    }, {
        $unwind: {
            path: "$pair"
        }
    }, {
        $project: {
            _id: 0,
            RecordID: "$_id",
            Department: "$departmentID",
            ChangeTime: "$pair.time",
            TimeSpent: {
                $subtract: ["$pair.time", "$time"]
            }
        }
    }
])

проблема с этимто, что он смешивает сопряжение действий между различными документами, не включает потраченное время до текущего времени и имеет так много распространений поверх использования представления в середине.

Структура данных может быть измененанемного, если нужно.

1 Ответ

0 голосов
/ 22 ноября 2018

Я действительно потратил 2 дня, пытаясь найти решение для этого, прежде чем опубликовать вопрос, и решил его несколько часов спустя.

Просто хотел поделиться своим решением, и если бы кто-нибудь мог оптимизировать его для производительностиили что-нибудь, пожалуйста, не стесняйтесь публиковать свои ответы тоже

Решение

оно использует функцию $zip для формирования пар действий после применения фильтрапутем передачи исходного массива событий и другой копии того же массива, исключая первый элемент, чтобы первый элемент соответствовал второму, а второй - третьему и т. д.Я также добавил значение по умолчанию для текущего времени, чтобы вычислить дельту последнего элемента из текущего времени.

db.test.aggregate([{
    $project: {
      RecordID: "$_id",
      history: {
        $filter: {
          input: "$ChangeHistory",
          as: "changeHistory",
          cond: {
            $or: [{
                $eq: ["$$changeHistory.ChangeType", 0]
              },
              {
                $eq: ["$$changeHistory.ChangeType", 2]
              }
            ]
          }

        }
      }
    }
  },
  {
    $addFields: {
      pairs: {
        $zip: { // here is the trick
          inputs: ["$history", {
            $slice: ["$history", 1, {
              $size: "$history"
            }]
          }],
          useLongestLength: true,
          defaults: [0, {
            ChangeTime: new Date()
          }]
        }
      }
    }
  },
  {
    $unwind: {
      path: "$pairs"
    }
  },
  {
    $project: {
      id: "$_id",
      old: {
        $arrayElemAt: ["$pairs", 0]
      },
      new: {
        $arrayElemAt: ["$pairs", 1]
      }
    }
  },
  {
    $project: {
      RecordID: "$id",
      Status: "$old.StatusId",
      TimeDeltaMS: {
        $subtract: ["$new.ChangeTime", "$old.ChangeTime"]
      },
      ChangeTime: "$new.ChangeTime"
    }
  },
])
...