5

Ich versuche, einen Teilindex Postgresql Jsonb Spalte hinzufügen. Die jsonb-Spalte heißt: email_provider. Ich habe versucht, einen Teilindex auf der Spalte wie unten gezeigt hinzuzufügen, aber es wirft anderen Fehler wie dieses PG :: UndefinedColumn: FEHLER: Spalte "email_povider" existiert nicht und zu anderen Zeiten wirft es den Fehler an: PG :: AmbiguousFunction : ERROR: Betreiber ist nicht eindeutig: unbekannt -> unbekanntErstellen Sie Partial-Index für Postgresql Jsonb-Feld

der Teilindex in der Schienen-5 Migration wie folgt aussieht:

add_index :accounts, :name, name: "index_accounts_on_email_provider_kind", using: :gin, where: "('email_provider' -> 'sparkpost' ->> 'smtp_host' = 'www.sparkpost.com') AND ('email_povider' -> 'amazon ses' ->> 'smtp_host' = 'www.awses.com')" 

die json für die email_provider Spalte sieht wie folgt aus:

{ 
    "email_provider": { 
    "sparkpost": { 
     "smtp_host": "www.sparkpost.com", 
     "smtp_port": "" 
     }, 
     "aws ses": { 
     "smtp_host": "www.amazon/ses.com ", 
     "smtp_port": " ", 
     "username": " ", 
     "password": " " 
     } 
    } 
} 

Die Tabelle sieht wie folgt aus:

class CreateAccounts < ActiveRecord::Migration[5.0] 
    def change 
     create_table :accounts do |t| 
     t.string :name, null: false 
     t.jsonb :email_provider, null: false 
     t.jsonb :social_account, default: '[]', null: false 
     t.timestamps 
    end 
     add_index :accounts, :name, name: "index_accounts_on_email_provider_kind", using: :gin, where: "('email_provider' -> 'sparkpost' ->> 'smtp_host' = 'www.sparkpost.com') AND ('email_povider' -> 'amazon ses' ->> 'smtp_host' = 'www.awses.com')" 

     add_index :accounts, :name, name: "index_accounts_on_social_account_type", using: :gin, where: " 'social_account' @> [{'type': 'facebook'}] AND 'social_account' @> [{'type': 'twitter'}]" 
    end 
end 

aktualisieren

Basierend auf leichte Anpassung an die akzeptierte Antwort unten, der Code, den ich btree nicht Gin Index erstellen bin mit in Schienen wird Activrecord unten gezeigt. Es schafft einen btree Index, weil wir die Namensspalte verwenden, die von String-Datentyp ist und nicht jsonb als here beschrieben:

add_index :accounts, :name, name: "index_accounts_on_name_email_provider", where: "email_provider -> 'sparkpost' ->> 'smtp_host' = 'www.sparkpost.com' AND email_provider -> 'amazon ses' ->> 'smtp_host' = 'www.awses.com' " 

add_index :accounts, :name, name: "index_accounts_on_name_social_account", where: " social_account @> '[{\"type\": \"facebook\"}]'::jsonb AND social_account @> '[{\"type\": \"twitter\"}]'::jsonb" 

Antwort

9

Ich glaube, Sie so etwas brauchen:

add_index :accounts, :email_provider, name: "index_accounts_on_email_provider_kind", using: :gin, where: "(email_provider -> 'email_provider' -> 'sparkpost' ->> 'smtp_host' = 'www.sparkpost.com') AND (email_provider -> 'email_povider' -> 'amazon ses' ->> 'smtp_host' = 'www.awses.com')" 

I‘ habe das zweite Argument von add_index zu :email_provider geändert, weil das der Spaltenname ist. Auch für die die where Klausel, änderte ich

'email_provider' -> 'sparkpost' ->> 'smtp_host' = 'www.sparkpost.com' 

zu

email_provider -> 'email_provider' -> 'sparkpost' ->> 'smtp_host' = 'www.sparkpost.com' 

weil der -> Betreiber erwartet es Argument links ein json (b) Wert zu sein, aber man bot eine Zeichenfolge. So z.B. email_provider -> 'email_provider' extrahiert den Wert email_provider aus der Spalte email_provider. Man beachte, dass diese letzte Zeile mehr geschrieben werden kann kompakt wie:

email_provider #>> '{email_provider,sparkpost,smtp_host}' = 'www.sparkpost.com' 

durch die #>> verwendet, die einen „Pfad“ Auszüge aus einem josn (b) Objekt. So ist die add_index Anweisung kann geschrieben werden als:

add_index :accounts, :email_provider, name: "index_accounts_on_email_provider_kind", using: :gin, where: "(email_provider #>> '{email_provider,sparkpost,smtp_host}' = 'www.sparkpost.com') AND (email_provider -> '{email_povider,amazon ses,smtp_host}' = 'www.awses.com')" 

Für Sie zweiten Index, sollten Sie versuchen, so etwas wie:

where: " social_account -> 'social_account' @> '[{\"type\": \"facebook\"}]'::jsonb AND social_account -> 'social_account' @> '[{\"type\": \"twitter\"}]'::jsonb" 

In diesem Fall habe ich das gleiche denken, mit der Säule wie in der ersten Fall. Ich änderte auch das rechte Argument von @>, das ein jsonb-Wert sein muss. Also müssen Sie es als JSON-String definieren, der doppelte Anführungszeichen für Strings benötigt (beachten Sie auch, dass wir sie für Ruby ausschließen müssen), und dann schreibe ich den String in jsonb, um den gewünschten Typ zu erhalten.

+0

Danke, ich werde das ausprobieren und auf Sie zurückkommen. Aber ich werde höchstwahrscheinlich den Index auf die Spalte ** name ** setzen, obwohl die Spalte jsonb ** email provider ** ist, weil die Abfrage schneller ist, wenn der Index in der Spalte ** name ** und dem ** steht. Dabei wird query ** verwendet, um unseren Index auf Treffer aus der jsonb-Spalte zu beschränken. Sie können diesen Ansatz hier erklärt sehen: http://blog.heapanalytics.com/speeding-up-postgresql-queries-with-partial-indexes/. – brg

+0

Vielen Dank. Ich habe den Index in der Spalte ** Name ** beibehalten. Die einzige Änderung war, ** mit:: gin ** zu entfernen, da der Index nicht direkt in der jsonb-Spalte steht. Der endgültige Code für einen der Indizes sieht dann wie folgt aus: ** add_index: accounts,: name, name: "index_accounts_on_name_email_provider", wobei: "(email_provider -> 'email_provider' -> 'sparkpost' - >> 'smtp_host' = ' www.sparkpost.com ') AND (email_provider ->' email_povider '->' amazon ses '- >>' smtp_host '=' www.awses.com ') "**, was einen ** btree partiellen Index ** erzeugt in der Spalte ** name **, die unsere Übereinstimmungen auf Attribute in der jsonb-Spalte beschränkt. – brg

Verwandte Themen