Fühlen Sie sich frei, alle Code zu schnappen, die Sie nützlich finden. Oder noch besser, Sie sind mehr als willkommen, ein Betreuer zu werden! Meine tiefste aufrichtige Entschuldigung dafür, dass dieses Projekt losgelassen hat. Ich hoffe, es verursacht Ihnen keine Unannehmlichkeiten.
Postgres Volltext-Suche in node.js mit sequelize as ORM.
Schauen Sie sich das Codebeispiel an.
Diese Bibliothek nutzt Postgres Volltext-Suche und materialisierte Ansichten, um schnelle, leistungsstarke und einfache Suchanfragen auszuführen. Es erstellt zunächst eine materialisierte Ansicht, indem alle Werte in den Feldern verkettet werden, die Sie durchsuchbar machen und sie in einen ts_vector umwandeln möchten. Anschließend fügt es einem searchByText und search -Methoden zu Ihrem Folgenmodell hinzu, mit dem Sie nur Suchvorgänge aus einer Abfrage -Zeichenfolge oder einem Abfragezeichenfolge und einem Optionen JSON -Objekt ausführen können. Außerdem werden eine refresh hinzugefügt, um die materialisierte Ansicht zu aktualisieren, wenn Updates an Ihrem Modell oder wann immer Sie möchten.
Nehmen wir beispielsweise an, wir haben eine Filmdatenbanktabelle, die:
| Ausweis | Name | Beschreibung | Stadt | Veröffentlichungsdatum | Bewertung |
|---|---|---|---|---|---|
| 1 | Der Flüchtling | Ein anderer Typ entkommt aus dem Gefängnis | Chicago | 1993-08-06 | 8 |
| 2 | Ein schöner Geist | Ein Film über einen Mathematiker | New York | 2001-12-05 | 8 |
| 3 | Chicago | Ein gutes ales amerikanisches Musical | Toronto | 2002-12-10 | 7 |
| 4 | Ewiger Sonnenschein des makellosen Geistes | Jim Carrey, wenn er kein Komiker ist | New York | 2004-03-19 | 8 |
Wir möchten die Suche nach Namen, Beschreibung und Stadt und Filterung durch Bewertung und Release_Date zulassen. Wir möchten auch die Ergebnisse nach Relevanz sortieren, indem wir dem Namen ein höheres Gewicht als Beschreibung und Stadt geben. Also, wenn Sie die Suche ausführen:
Film . searchByText ( "Chicago" ) ; // Returns [ Chicago, The Fugitive ]Die Ergebnisse mit dem Wort "Chicago" im Titel erscheinen vor denen mit demselben Wort in der Beschreibung oder Stadt. So würde der Film Chicago zuerst erscheinen, und der Flüchtling wäre der zweite.
Wir können auch Filterung und Bestellung durch ein bestimmtes Feld hinzufügen, anstatt durch Relevanz zu bestellen, indem wir die Suchabfrage durchführen:
Film . searchByText ( "Mind order:releaseDate" ) ; // Returns [ A Beautiful Mind, Eternal Sunshine of the Spotless Mind ]
// or
Film . searchByText ( "Mind releaseDate:<2002-01-01" ) ; // Returns [ A Beautiful Mind ]Sie sind auch nicht nur auf die Felder eines Modells beschränkt. Sie können auch Felder aus zugehörigen Modellen einfügen. Wenn wir beispielsweise ein anderes Modell in unserer Datenbank namens Actor hatten, das von einem Fremdschlüssel mit Film zugeordnet ist, können wir Felder aus dem Schauspielermodell in die materialisierte Ansicht von Film einbeziehen. Auf diese Weise können wir Suchvorgänge ausführen, z. B.:
Film . searchByText ( "Tom Hanks" ) ; // Returns Tom Hanks moviesMit dieser Bibliothek können Sie noch mehr anfangen. Weitere Informationen zur Installation und Verwendung finden Sie in den Abschnitten für Installation und Nutzung. Zur Dokumentation finden Sie den Abschnitt "Dokumentation".
NPM Installieren Sie das pg-search-sequelize -Paket
npm i --save pg-search-sequelizeDann benötigen Sie diese in Ihrer materialisierten Ansichtsmodell -Definitionsdatei und geben Sie das Folgenmodell an, um es durchsuchbar zu machen:
let MyModel = sequelize . define ( ... ) ; // your sequelize model definition
let SearchModel = require ( 'pg-search-sequelize' ) ; // Require the pg-search-sequelize library
MyModel = new SearchModel ( MyModel ) ; // Construct a SearchModel out of the model you defined above. This adds `search`, `searchByText`, and `refresh` class methods to your model.Weitere Informationen finden Sie in der Verwendung, um Ihr Modell zu definieren und die materialisierte Ansicht zu erstellen.
Jetzt, da Sie einen kleinen Einblick in das, was diese Bibliothek Ihnen am Ende ermöglicht, gehen wir zu den Setup -Schritten:
Wenn Sie das Folgen -Migrations -Tool verwenden, können Sie die von der createMaterializedView(name, referenceModel, attributes, options) bereitgestellte Helferfunktion verwenden, die von der Klasse QueryInterface bereitgestellt werden:
const QueryInterface = require ( "pg-search-sequelize" ) . QueryInterface ;
const models = require ( "../models" ) ;
// The model we're creating the materialized view for
const referenceModel = models . Film ;
const materializedViewName = "film_materialized_view" ;
const attributes = { // field: weight. Every field has a weight to calculate how relevant the search results are.
name : "A" , // name has the highest weight.
description : "B" ,
city : "C" // city has a lower weight than title and description
}
const options = {
include : [ // You can also include fields from associated models
{
model : models . Actor ,
foreignKey : "actor_id" ,
targetKey : "id" ,
associationType : "hasMany" , // association types are: belongsTo, hasOne, or hasMany
attributes : { // Those attributes get added to the materialized view's search document and will also be searched just like the other fields
first_name : "D" ,
last_name : "D" ,
date_of_birth : "D"
}
}
]
}
module . exports : {
up : queryInterface => new QueryInterface ( queryInterface ) . createMaterializedView ( materializedViewName , referenceModel , attributes , options ) ,
down : queryInterface => new QueryInterface ( queryInterface ) . dropMaterializedView ( materializedViewName )
}Wenn Sie das Folgen -Migration -Tool nicht verwenden, können Sie die materialisierte Ansicht auf jede Art und Weise erstellen, die Sie bevorzugen.
Definieren Sie das Modell Ihrer materialisierten Ansicht genauso wie Sie alle anderen Folgenmodelle definieren. Der einzige Unterschied besteht darin, dass Sie Ihren Modelldefinitionoptionen referenceModel -Eigenschaft hinzufügen müssen. Erstellen Sie dann einfach ein SearchModel aus dem gerade definierten materialisierten Ansichtsmodell.
let SearchModel = require ( "pg-search-sequelize" ) ;
let FilmMaterializedView = sequelize . define ( 'FilmMaterializedView' , {
name : DataTypes . STRING ,
rating : DataTypes . INTEGER ,
document : DataTypes . TEXT
} , {
referenceModel : models . Film // The model for which we're defining the materialized view
} ) ;
FilmMaterializedView = new SearchModel ( FilmMaterializedView ) ; // Adds search, searchByText, and refresh class methods to the model. Jetzt können Sie materializedViewModel.search(query, options) oder materializedViewModel.searchByText(query) aufrufen, um eine Volltext-Suche in Ihrem Modell und seinen Assoziationen auszuführen.
models . Film . searchByText ( "Mind" ) ; // Returns [ A Beautiful Mind, Eternal Sunshine of the Spotless Mind ]
// The following command searches for instances that match the search query,
// filters by those with releaseDate later than 2002, and orders the results by name field
models . Film . searchByText ( "Mind releaseDate:>2002 order:name" ) ; // Returns [ Eternal Sunshine of the Spotless Mind ]
// Or if you don't like strings, you can pass those properties in a JSON object
// The following returns the same as the code above; i.e. [ Eternal Sunshine of the Spotless Mind ]
models . Film . search ( "Mind" , {
where : {
releaseDate : { operator : ">" , value : "2002-01-01" }
} ,
order : [ [ "name" , "ASC" ] ]
}Vergessen Sie nicht, die materialisierte Ansicht zu aktualisieren, um sie mit den neuesten Änderungen an Ihrem Modell zu aktualisieren. Eine Möglichkeit, dies zu tun, besteht darin, einen Nachkratzer, AfterUpdate und Afterdelete -Haken an Ihrem Modell zu erstellen, um die materialisierte Ansicht zu aktualisieren:
sequelize . define ( 'Film' , attributes , {
hooks : {
afterCreate : ( ) => FilmMaterializedView . refresh ( ) ,
afterUpdate : ( ) => FilmMaterializedView . refresh ( ) ,
afterDelete : ( ) => FilmMaterializedView . refresh ( )
}
} ) ;Alternativ können Sie einen Jobplaner haben, der Ihre materialisierte Ansicht jede x -Zeit aktualisiert.
Besuchen Sie den Abschnitt "Dokumentation", um zu erfahren, welche Art von Suchanfragen Sie durchführen können.
PG Search - Sequelize verfügt über 2 Klassen, SearchModel und QueryInterface .
Die SearchModel -Klasse ist das, was Sie verwenden würden, um die Such- und Aktualisierungsklassenmethoden zu Ihrem Fortsetzung von materialisierten Ansicht hinzuzufügen. So greifen Sie auf die SearchModel -Klasse require("pg-search-sequelize") . Die folgenden Funktionen können aus dem Modell aufgerufen werden, das Sie mit der SearchModel -Klasse MyModel = new SearchModel(MyModel) konstruieren.
Suchen Sie das materialisierte Ansichtsmodell mithilfe einer Suchabfrage -Zeichenfolge und einem Optionsobjekt.
query - Die Suchabfragezeichenfolge.optionswhere - Filter, um die Ergebnisse durch zu begrenzen. /*
Format:
options.where = {
attribute: {
operator: ">, <, =, >=, <=, @@, ilike, etc.",
value: "some value"
}
*/
// Example:
options . where = {
releaseDate : {
operator : ">" ,
value : "2012-01-01"
}
}attributes - ein Array der zurückgegebenen Attribute. ex. options . attributes = [ "name" , "releaseDate" , "rating" ]order - Ein Array von Arrays, wobei der erste Wert der Attributname ist und der zweite die Richtung ist. Zum Beispiel: options . order = [
[ "name" , "ASC" ] ,
[ "releaseDate" , "DESC" ] ,
[ "rating" , "DESC" ]
] Promise - Ein Array der Suchergebnisseinstanzen mit den im Optionsobjekt angegebenen Attributen, dem defaultScope des materialisierten Ansichtsmodells oder allen Attributen in der materialisierten Ansichtsmodelldefinition.
Suchen Sie materialisierte Ansichtsmodell nur mit einer Textabfrage. Dies ist besonders nützlich, um einen Such -API -Endpunkt Ihrem Modell auszusetzen, sodass Sie sich keine Sorgen machen müssen, die Suchabfrage -Zeichenfolge zu analysieren.
query - Eine Zeichenfolge des Abfragetextes, Filter und Felds zum Bestellen. // --------------
// Simple search
// --------------
Film . searchByText ( "Beautiful" ) ; // WHERE to_tsquery('Beautiful') @@ document
// --------------
// Ordering
// --------------
// Search and order the results by rating in ascending order
Film . search ( "Beautiful order:rating" ) ; // WHERE to_tsquery('Beatiful') @@ document ORDER BY ts_rank(document, to_tsquery('Beautiful')), rating ASC
// Or to invert the order to descending order, prepend the field name by an exclamation point
Film . searchByText ( "Beautiful order:!rating" ) ; // WHERE to_tsquery('Beatiful') @@ document ORDER BY ts_rank(document, to_tsquery('Beautiful')), rating DESC
// --------------
// Filtering
// --------------
// Searches for a movie that has the text "Beautiful" in any of its fields and "brilliant mathematician" in the description.
Film . searchByText ( "Beatiful description:brilliant mathematician" ) ; // WHERE to_tsquery('Beatiful') @@ document AND description ILIKE %brilliant mathematician%
// You can also use comparison operators: =, >, <. >=, <=
Film . searchByText ( "Beautiful rating:>=7" ) // WHERE to_tsquery('Beautiful') @@ document AND rating >= 7
// If no operator is passed to the filter, an ILIKE operator is used. Just as seen in the first filtering example.
// If the field's type doesn't work with ILIKE, it is cast to TEXT.
Film . searchByText ( "Beautiful releaseDate:200" ) // WHERE to_tsquery('Beautiful') @@ document AND release_date::TEXT ILIKE 200 Promise - Ein Array der Suchergebnisseinstanzen mit den defaultScope -Attributen des materialisierten Ansichtsmodells oder alle Attribute in der Definition des materialisierten Ansichtsmodells.
Erfrischt die materialisierte Ansicht. ex. models.Film.afterCreate(() => MaterializedViews.Film.refresh())
Die QueryInterface -Klasse ist zum Ausführen von Migrationen gedacht. dh erstellen und fallen lassen die materialisierte Ansicht. So greifen Sie auf die QueryInterface -Klasse require("pg-search-sequelize").QueryInterface in Ihren up und down Funktionen, konstruieren Sie eine Instanz und geben Sie die Folge- queryInterface an:
let QueryInterface = require ( "pg-search-sequelize" ) . QueryInterface ;
module . exports = {
up : queryInterface => new QueryInterface ( queryInterface ) . createMaterializedView ( ... ) ,
down : queryInterface => new QueryInterface ( queryInterface ) . dropMaterializedView ( ... ) ,
} ; Erstellt eine neue materialisierte Ansicht in der Datenbank mit zwei Feldern; ID und Dokument. Das Dokumentfeld ist ein ts_vector des verketteten Textes aller angegebenen Attribute/Felder, die durchsuchbar sind
name - Der Name der materialisierten Ansichtmodel - Das Modell der Tabelle zum Erstellen der materialisierten Ansicht für.attributes - Schlüsselwertpaarobjekt, wobei der Schlüssel der Name des Feldes und das Wert des Feldes des Feldes ist. attributes = {
name : "A" // "A" is the highest weight
description : "B" ,
release_date : "C"
city : "D" // "D" is the lowest possible weight
}options tableName - Wenn tableName zur Verfügung steht
primaryKeyField - Wenn es zur Verfügung gestellt wird, ist das primaryKeyField des bestandenen Modells außer Kraft gesetzt
include - eine Reihe von Objekten, die die Attribute der zugehörigen Modelle in das Dokument der materialisierten Ansicht definieren.
include = [
{
model : models . Actor ,
foreignKey : "actor_id" ,
target_key : "id" ,
associationType : "hasMany" ,
attribtues : {
first_name : "C" ,
last_name : "C"
} ,
include : [ ... ] // optionally you can include models associated to the Actor model
} ,
// ...
// Other associated models
]model - das Modell, das einbeziehtforeignKey - Der Foreignkey, der auf das zugehörige Modell hinweist. Beachten Sie, dass der Fremdschlüssel basierend auf dem Assoziationstyp auf dem Referenzmodell (dem Filmmodell im obigen Beispiel) oder auf dem anderen Modell (dem Schauspielermodell) stehen kann.targetKey - der Schlüssel, auf den sich auf die Foreignkey bezieht.associationType - Der Assoziationstyp aus der Sicht des Referenzmodells (Film). Es muss hasOne , hasMany oder belongsTo sein.attributes - Die Attribute, die aus dem Modell aufgenommen werden sollen.include - ein inklusives Array von Modellen, die dem eingeschlossenen Modell zugeordnet sind (z. Lässt die materialisierte Ansicht fallen.
name - Der Name der materialisierten Ansicht