ClickHouse : colonne MATERIALIZED non accessible via VIEW
Problème
Quand une VIEW ClickHouse sélectionne des colonnes spécifiques d'une table (pas SELECT *), les colonnes MATERIALIZED ou ALIAS non explicitement incluses dans la liste SELECT de la vue sont invisibles aux requêtes qui passent par la vue. Tenter WHERE v.materialized_col = ? sur une telle vue produit une erreur « column not found », qui remonte sous forme d'HTTP 500 dans les couches API.
Contexte / Conditions de déclenchement
- Vous ajoutez un nouveau filtre de requête (par ex.
?platform=vine) qui référence une colonne via un alias de vue - La colonne est définie comme
String MATERIALIZED ...sur la table sous-jacente - La VIEW a été créée avec une liste de colonnes explicite (pas
SELECT *) - La colonne fonctionne correctement lors d'une requête directe sur la table de base
- L'API retourne HTTP 500 sans message d'erreur utile au client
- Les logs serveur affichent une erreur ClickHouse « column not found » ou similaire
Solution
Option A : Sous-requête (Aucune migration requise)
Remplacez la référence directe de colonne par une sous-requête contre la table de base :
-- CASSÉ : la vue n'expose pas 'platform'
WHERE v.platform = ?
-- CORRIGÉ : sous-requête contre la table de base où la colonne MATERIALIZED existe
WHERE v.id IN (
SELECT id FROM events_deduped
WHERE platform = ? AND kind IN (34235, 34236)
)
Option B : Migration (Plus propre à long terme)
Créez une nouvelle migration qui supprime et recrée la vue pour inclure la colonne :
DROP VIEW IF EXISTS nostr.videos;
CREATE VIEW nostr.videos AS
SELECT
id, pubkey, created_at, kind, content, tags, sig, indexed_at,
d_tag, title, thumbnail, video_url, author_name, loops,
platform, -- AJOUTER LA COLONNE MATERIALIZED
if(published_at > 0, published_at, toUnixTimestamp(created_at)) AS published_at,
expiration_at
FROM nostr.events_deduped FINAL
WHERE kind IN (34235, 34236);
Avertissement : La suppression d'une vue en cascade — toute vue dépendante (video_stats, trending_videos, videos_with_loops, etc.) doit aussi être supprimée et recréée dans le bon ordre de dépendances.
Vérification
- Interrogez la vue directement :
SELECT platform FROM videos LIMIT 1— devrait retourner des données (ou chaîne vide pour non-vine) - L'appel API avec le paramètre de filtre retourne 200 au lieu de 500
- Exécutez la suite complète de tests de régression pour confirmer l'absence de régressions
Exemple (Funnelcake)
La vue nostr.videos (migration 000060) sélectionne une liste de colonnes fixe depuis events_deduped. La colonne platform est String MATERIALIZED sur events_deduped mais pas dans la vue.
La PR #85 a ajouté v.platform = ? à get_recent_videos_with_events() et get_trending_videos_with_events(), qui interrogent toutes deux FROM videos v. Cela a causé HTTP 500 pour toute requête avec ?platform=vine.
Correction (PR #86) : Changé pour l'approche sous-requête. Notez que videos_with_loops (une vue différente) INCLUT platform — les requêtes passant par cette vue (comme get_videos_filtered) fonctionnent correctement.
Notes
- Les colonnes
MATERIALIZEDsont physiquement stockées mais accessibles uniquement si explicitement sélectionnées - Les colonnes
ALIASsont calculées à la lecture et ont la même contrainte de visibilité dans les vues - Vérifiez toujours la définition de la vue avant d'ajouter des conditions WHERE sur des colonnes
- La vue
videos_with_loopsinclut plus de colonnes quevideos— vérifiez quelle vue votre requête utilise réellement - Dans Funnelcake : vue
videos= colonnes minimales ;videos_with_loops= colonnes complètes incluant platform