Контекст:
У меня есть таблица test
:
=> \d+ test
Table "public.test"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
---------------+------------------------+-----------+----------+---------+----------+--------
------+-------------
id | character varying(255) | | | | extended |
|
configuration | jsonb | | | | extended |
|
Столбец configuration
содержит «четко определенный» json, который имеетключ называется source_url
(пропуск других не относящихся ключей).Пример значения для столбца configuration
:
{
"source_url": "https://<resource-address>?Signature=R1UzTGphWEhrTTFFZnc0Q4qkGRxkA5%2BHFZSfx3vNEvRsrlDcHdntArfHwkWiT7Qxi%2BWVJ4DbHJeFp3GpbS%2Bcb1H3r1PXPkfKB7Fjr6tFRCetDWAOtwrDrVOkR9G1m7iOePdi1RW%2Fn1LKE7MzQUImpkcZXkpHTUgzXpE3TPgoeVtVOXXt3qQBARpdSixzDU8dW%2FcftEkMDVuj4B%2Bwiecf6st21MjBPjzD4GNVA%2F6bgvKA6ExrdYmM5S6TYm1lz2e6juk81%2Fk4eDecUtjfOj9ekZiGJVMyrD5Tyw%2FTWOrfUB2VM1uw1PFT2Gqet87jNRDAtiIrJiw1lfB7Od1AwNxIk0Rqkrju8jWxmQhvb1BJLV%2BoRH56OHdm5nHXFmQdldVpyagQ8bQXoKmYmZPuxQb6t9FAyovGMav3aMsxWqIuKTxLzjB89XmgwBTxZSv5E9bkWUbom2%2BWq4O3%2BCrVxYwsqg%3D%3D&Expires-At=1569340020&Issued-At=1568293200"
.
.
}
URL содержит параметр запроса Expires-At
Проблема: Существует запланированная работа, которая выполняется каждые 24 часа.Эта работа должна найти все такие записи, срок действия которых истек или вот-вот истечет (а затем что-то с этим сделать).
Решение:
У меня есть этот запрос, чтобы получить мойзадание выполнено:
select * from test where to_timestamp(split_part(split_part(configuration->>'source_url', 'Expires-At=', 2), '&', 1)::bigint) <= now() + interval '24 hours';
Объяснение:
- Запрос сначала разбивает
source_url
на Expires-At=
и выбирает присутствующую деталь справазатем он разделяет результирующую строку на &
и выбирает левую ее часть, получая точное время эпохи, необходимое для text
- Тот же запрос также работает для углового случая, когда
Expires-At
является последним параметром запроса в source_url
- . Как только он извлекает время эпохи как
text
, он сначала преобразует его в bigint
, а затем преобразует его в метку времени Postgres, а затем эта метка времени сравнивается, еслионо будет меньше или равно времени в 24 часах от now()
- Все строки, проходящие вышеупомянутое условие, выбраны
Таким образом, в конце, в каждомrun, scheduler обновляет все URL, срок действия которых истекает в следующие 24часов (включая те, которые уже истекли)
Вопросы: - Хотя это решает мою проблему, мне действительно не нравится это решение.Здесь много манипуляций со строками, которые я нахожу не чистыми.Есть ли более чистый способ сделать это?
- Если мы «должны» перейти к описанному выше решению, можем ли мы даже использовать индексы для такого рода запросов?Я знаю, что функции
lower()
, upper()
extra могут быть проиндексированы, но я действительно не могу придумать, как можно проиндексировать этот запрос.
Альтернативы:
Если не будет действительно чистого решения, я пойду с этим:
- Я бы ввел новый ключ внутри
configuration
json под названием expires_at
, убедившись, чтоэто заполнено правильным значением, каждый раз, когда вставляется строка. - И затем непосредственно запрашивает это вновь добавленное поле (индекс имеет столбец
configuration
).
Iпризнаю, что таким образом я повторяю информацию Expires-At
, но из всех возможных решений, которые я мог придумать, это то, что я считаю наиболее чистым.
Есть ли лучший способ, чем этот, которыйвы, ребята, можете думать о?
РЕДАКТИРОВАТЬ: Обновлен запрос для использования substring()
с регулярным выражением вместо внутреннего split_part()
:
select * from test where to_timestamp(split_part(substring(configuration->>'source_url' from 'Expires-At=\d+'), '=', 2)::bigint) <= now() + interval '24 hours';