PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

SQLAlchemy Textabgleich von Daten im JSON-Feld mit UTF-8

Das Problem liegt in cast(Unicode) eines Postgresql json Säule. Es wandelt einfach den json um auf den Texttyp, der Unicode von SQLAlchemy zugrunde liegt , im Falle von Postgresql VARCHAR . Mit anderen Worten, es erzeugt eine Zeichenfolgendarstellung von JSON, anstatt den Textinhalt zu extrahieren. Wenn Ihre Eingabe maskierte Unicode-Codepoints enthielt, werden sie wie in diesem Fall ausgegeben. Gegeben sei ein einfacher Test Modell mit einem json Spalte Daten :

In [7]: t = Test(data={'summary': 'Tämä on summary.'})

In [8]: session.add(t)

In [9]: session.commit()

In [11]: session.query(Test.data['summary'].cast(Unicode)).scalar()
Out[11]: '"T\\u00e4m\\u00e4 on summary."'

Es sollte offensichtlich sein, warum eine Übereinstimmung mit Unicode-Zeichen ohne Escapezeichen fehlschlägt. Der korrekte Weg, den Textinhalt zu extrahieren, ohne Escape-Unicode zu maskieren, ist die Verwendung von astext , das den ->> verwendet Betreiber in Postgresql:

In [13]: session.query(Test.data['summary'].astext).scalar()
Out[13]: 'Tämä on summary.'

Zitieren der JSON-Dokumentation zu Funktionen und Operatoren:

Also in deinem Fall:

Message.query.\
    filter(Message.content['summary'].astext.match(term))

Beachten Sie, dass dies nur für json gilt type, nicht jsonb , weil der json Typ konvertiert keine Unicode-Escapezeichen bei der Eingabe. jsonb andererseits konvertiert alle Unicode-Escapes in äquivalentes ASCII oder UTF-8 Zeichen zum Speichern . Wenn unser Test model enthielt eine zweite Spalte data2 jsonb , mit genau der gleichen Eingabe, dann wäre das Ergebnis:

In [11]: session.query(Test.data['summary'].cast(Unicode),
    ...:               Test.data2['summary'].cast(Unicode)).first()
Out[11]: ('"T\\u00e4m\\u00e4 on summary."', '"Tämä on summary"')

Trotzdem sollten Sie astext verwenden , wenn Sie Text anstelle einer JSON-Zeichenfolgendarstellung wünschen.