Мой вопрос касается оптимизации устаревших данных во вложенном документе с использованием Mongo, я использую реализацию Java, но я не думаю, что это имеет значение.
Я использовал коллекцию stat для отслеживаниямои статистические данные за минуту, месяц, год и общее количество, и у каждой статистики есть свой собственный документ, например, именем статистики может быть «память» или «запросы», что угодно.
Вот пример ...
{
"_id" : ObjectId("5b47269748cbb4a1e57d5f0a"),
"stat" : "my-stat-1",
"app" : {
"total" : {
"total" : NumberLong(15201),
"yearly" : {
"2018" : 8396,
"2019" : NumberLong(6805)
},
"monthly" : {
"Jul 2018" : 306,
"Aug 2018" : 389,
"Sep 2018" : 107,
"Oct 2018" : 6959,
"Nov 2018" : 532,
"Dec 2018" : 103,
"Jan 2019" : 67
},
"minutes" : {
"2019-10-28T15:06" : 1,
"2019-10-29T15:07" : 1,
"2019-10-28T15:08" : 2,
"2019-10-28T15:09" : 3,
"2019-10-28T15:11" : 2,
"2019-10-28T15:12" : 2,
"2019-10-28T15:25" : 3,
"2019-10-28T15:26" : 9,
"2019-10-28T15:27" : 2,
"2019-10-28T16:48" : 5
}
},
"api-1" : {
"total" : 713,
"yearly" : {
"2018" : 187,
"2019" : 526
},
"monthly" : {
"Jul 2018" : 71,
"Aug 2018" : 77,
"Sep 2018" : 3,
"Nov 2018" : 12,
"Dec 2018" : 24,
},
"minutes" : {}
},
"api-2" : {
"total" : 3490,
"yearly" : {
"2018" : 1021,
"2019" : 2469
},
"monthly" : {
"Jul 2018" : 211,
"Aug 2018" : 119,
"Sep 2018" : 37,
"Oct 2018" : 77,
"Nov 2018" : 499,
"Dec 2018" : 78,
"Jan 2019" : 66,
},
"minutes" : {
"2019-10-28T20:10" : 14,
"2019-10-28T20:11" : 1,
"2019-10-28T20:20" : 18,
"2019-10-28T20:21" : 3,
"2019-10-28T20:22" : 3,
"2019-10-30T11:45" : 3,
"2019-10-30T17:02" : 7,
"2019-10-30T19:55" : 20
}
},
...
}
}
Я пытался сфокусировать «документ», собрав все соответствующие статистические данные, я мог бы использовать коллекцию с такой структурой. .
- дата (минутная детализация)
- statName
- значение
Но преимущество в моем объектно-ориентированном подходе заключалось в том, что я моглегко получить мои ежемесячные, годовые и общие статистические данные без агрегации, плюс я получаю все свои соответствующие статистические данные обратно в одном красиво упакованном документе.
Мой сервис карт просто подключится к app.total. а затем очень быстро перечислите значения - это работает хорошо.
Проблема в том, что это реальная боль, когда дело доходит до удаления устаревших минутных данных (я не планирую удалять ежемесячную или годовую статистику).
Я думаю, что сделал ошибку, чтобы сохранить статистику мелкой детализации в объекте, а не в массиве, но я действительно, действительно, не хочу сейчас менять структуру. Я хочу узнать, могу ли я эффективно работать с тем, что у меня есть.
Преимущество использования структуры объекта для статистики минут заключается в том, что я могу использовать операторы обновления $ min и $ max для условного обновлениязаписи, например, чтобы перезаписать статистику только в том случае, если новое значение больше, чем постоянная запись eixsting. Поскольку существует более одного сервера, и поскольку я не хотел выполнять чтение в первую очередь, это казалось хорошим способом справиться с этим. Вот где профессионалы, кажется, останавливаются!
Я всегда говорил, что мелкие детали гранулярности будут полезны для максимума в 2-3 дня, поэтому я ранее написал метод, который удалял минуты, перебирая мои 'сбор статистики, затем попытка удалить любые «минуты» старше двух дней.
Проблема, которую я обнаружил, заключалась в том, что я не смог найти способ подстановки вложенных полей для сброса, особенно когда я не знаюзаранее, какие ключи API существуют в документе, например что-то вроде этого ...
db.getCollection("stats").update{},{"$unset":{"app.*.minutes.2019-10-28*",""})
Я не знаю, что находится в объекте, пока не прочитал весь этот чертов документ, но на самом деле я не знаюЯ хочу, чтобы весь документ вернулся, чтобы посмотреть, что нужно удалить.
Что было бы полезно, если бы я мог создать проекцию, в которой говорилось бы: «найдите мне все дочерние узлы в приложении на максимальной глубине одного», этоПозвольте мне обнаружить имена API без загрузки во всей статистике. например, что-то вроде этого ...
db.getCollection("stats").find({},{"app.*":1})
, чтобы выставить
"app.total"
"app.api-1"
"app.api-2"
Теоретически, я мог бы построить выражение модификации $ unset для этих путей, например, какое-то поле регулярного выражения(хотя это не похоже на то, что это возможно) ...
"app.total.minutes.2019-10-28*"
"app.api-1.minutes.2019-10-28*"
"app.api-2.minutes.2019-10-28*"
Но, учитывая проблему с регулярным выражением, мне, возможно, придется гидратировать их, чтобы $ 5 сбрасывал устаревший период, как этот ...
"app.total.minutes.2019-10-28T15:01"
"app.total.minutes.2019-10-28T15:02"
"app.total.minutes.2019-10-28T15:03"
"app.total.minutes.2019-10-28T15:04"
"app.total.minutes.2019-10-28T15:05"
но тогда я должен был бы повторить, что для каждого ключа API также внутри коллекции статов 10
Мое текущее решение - загрузить полную коллекцию "my-stat-1" в память,затем я перебираю набор ключей 'app', затем перебираю набор ключей 'minutes' и, если дата старше 2 дней, я добавляю его в список, который затем $ отменяет весь список одним оператором.
Это, конечно, неэффективно, но, не меняя структуру документа, стоит ли что-то еще, что я должен рассмотреть, чтобы вообще оптимизировать удаление старых минутных записей?