N'hésitez pas à saisir tous les morceaux de code que vous trouvez utiles. Ou mieux encore, vous êtes plus que bienvenu pour devenir un mainteneur! Mes excuses sincères les plus profondes pour avoir laissé partir ce projet. J'espère que cela ne vous provoque aucun inconvénient.
Postgres Recherche de texte intégral dans Node.js en utilisant Sequelize comme son orm.
Consultez l'exemple de code.
Cette bibliothèque utilise des vues de recherche en texte intégral Postgres pour exécuter des requêtes de recherche rapides, puissantes et simples. Il crée d'abord une vue matérialisée en concaténant toutes les valeurs des champs que vous souhaitez rendre consultables et les converties en ts_vector . Il ajoute ensuite une searchByText et de recherche search à votre modèle séquette, qui vous permettent d'exécuter les recherches à partir d'une chaîne de requête uniquement, ou une chaîne de requête et un objet JSON Options. Il ajoute également une méthode de classe refresh pour actualiser la vue matérialisée lorsque les mises à jour sont effectuées sur votre modèle ou quand vous le souhaitez.
Par exemple, supposons que nous avons une table de base de données de films qui a:
| identifiant | nom | description | ville | release_date | notation |
|---|---|---|---|---|---|
| 1 | Le fugitif | Un autre gars s'échappe de la prison | Chicago | 1993-08-06 | 8 |
| 2 | Un bel esprit | Un film sur un mathématicien | New York | 2001-12-05 | 8 |
| 3 | Chicago | Une bonne vieille comédie musicale américaine | Toronto | 2002-12-10 | 7 |
| 4 | Soleil éternel de l'esprit sans tache | Jim Carrey quand il n'est pas comédien | New York | 2004-03-19 | 8 |
Nous voulons permettre la recherche par le nom, la description et la ville et le filtrage par note et release_date. Nous voulons également trier les résultats par pertinence en donnant au champ de nom un poids plus élevé que la description et la ville. Donc, si vous exécutez la recherche:
Film . searchByText ( "Chicago" ) ; // Returns [ Chicago, The Fugitive ]Les résultats avec le mot "Chicago" dans le titre apparaissent devant ceux qui ont le même mot dans la description ou la ville. Ainsi, le film Chicago apparaîtrait en premier, et le fugitif serait le deuxième.
Nous pouvons également ajouter du filtrage et de la commande par un certain champ au lieu de commander par pertinence en faisant la requête de recherche:
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 ]Vous n'êtes pas non plus limité aux seuls champs d'un modèle; Vous pouvez également inclure des champs des modèles associés. Par exemple, si nous avions un autre modèle dans notre base de données appelée Actor qui est associé au film par une clé étrangère, nous pouvons inclure des champs du modèle d'acteur pour être dans la vue du film. Cela nous permet d'exécuter des recherches telles que:
Film . searchByText ( "Tom Hanks" ) ; // Returns Tom Hanks moviesVous pouvez faire plus avec cette bibliothèque. Pour plus de détails sur la façon d'installer et de l'utiliser, consultez les sections d'installation et d'utilisation. Pour la documentation, consultez la section Documentation.
NPM Installez le package pg-search-sequelize
npm i --save pg-search-sequelizeEnsuite, il faut le nécessiter dans votre fichier de définition de modèle de vue matérialisé et passez-lui le modèle séquestre pour le rendre consultable:
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.Veuillez vous référer à l'utilisation pour définir votre modèle et comment créer la vue matérialisée.
Maintenant que vous avez un aperçu de ce que cette bibliothèque vous permet à la fin, passons aux étapes de configuration:
Si vous utilisez l'outil Sequelize Migrations, vous pouvez utiliser la fonction d'assistance createMaterializedView(name, referenceModel, attributes, options) fournis par la classe QueryInterface :
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 )
}Si vous n'utilisez pas l'outil de migration séquestre, n'hésitez pas à créer la vue matérialisée de toutes les manières préférées.
Définissez le modèle de votre vue matérialisée de la même manière que vous définissez tous les autres modèles de séquelle. La seule différence est que vous devez ajouter une propriété referenceModel à vos options de définition de modèle. Ensuite, construisez simplement un SearchModel à partir du modèle de vue matérialisé que vous venez de définir.
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. Vous pouvez maintenant appeler materializedViewModel.search(query, options) ou materializedViewModel.searchByText(query) pour exécuter une recherche en texte intégral sur votre modèle et ses associations.
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" ] ]
}N'oubliez pas de rafraîchir la vue matérialisée pour la mettre à jour avec les dernières modifications apportées à votre modèle. Une façon de le faire consiste à créer un crochet après-procédure, après-update et après-service sur votre modèle pour actualiser la vue matérialisée:
sequelize . define ( 'Film' , attributes , {
hooks : {
afterCreate : ( ) => FilmMaterializedView . refresh ( ) ,
afterUpdate : ( ) => FilmMaterializedView . refresh ( ) ,
afterDelete : ( ) => FilmMaterializedView . refresh ( )
}
} ) ;Alternativement, vous pouvez avoir un planificateur de travaux qui rafraîchit votre vue matérialisée chaque durée X.
Rendez-vous sur la section Documentation pour savoir quel type de recherches vous pouvez effectuer.
PG Search - Sequelize a 2 classes, SearchModel et QueryInterface .
La classe SearchModel est ce que vous utilisez pour ajouter les méthodes de recherche de recherche et de rafraîchissement à votre modèle de séquelle de vue matérialisé. Pour accéder à la classe SearchModel require("pg-search-sequelize") . Les fonctions suivantes peuvent être appelées à partir du modèle que vous construisez avec la classe SearchModel MyModel = new SearchModel(MyModel)
Recherchez le modèle de vue matérialisée à l'aide d'une chaîne de requête de recherche et d'un objet Options.
query - La chaîne de requête de recherche.optionswhere - filtre pour limiter les résultats par. /*
Format:
options.where = {
attribute: {
operator: ">, <, =, >=, <=, @@, ilike, etc.",
value: "some value"
}
*/
// Example:
options . where = {
releaseDate : {
operator : ">" ,
value : "2012-01-01"
}
}attributes - Un tableau des attributs à retourner. ex. options . attributes = [ "name" , "releaseDate" , "rating" ]order - Un tableau de tableaux avec la première valeur étant le nom d'attribut et le second étant la direction. Par exemple: options . order = [
[ "name" , "ASC" ] ,
[ "releaseDate" , "DESC" ] ,
[ "rating" , "DESC" ]
] Promise - un tableau des instances de résultats de recherche avec les attributs spécifiés dans l'objet Options, le defaultScope du modèle de vue matérialisé, ou tous les attributs de la définition du modèle de vue matérialisé.
Recherchez le modèle de vue matérialisée avec une requête de texte uniquement. Ceci est particulièrement utile pour exposer un point de terminaison de l'API de recherche à votre modèle, vous n'avez donc pas à vous soucier de l'analyse de la chaîne de requête de recherche.
query - Une chaîne du texte de la requête, des filtres et du champ à commander. // --------------
// 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 - Un tableau des instances de résultats de recherche avec les attributs defaultScope du modèle de vue matérialisé, ou tous les attributs de la définition du modèle de vue matérialisé.
Rafraîchit la vue matérialisée. ex. models.Film.afterCreate(() => MaterializedViews.Film.refresh())
La classe QueryInterface est destinée à exécuter des migrations; c'est-à-dire la création et la suppression de la vue matérialisée. Pour accéder à la classe QueryInterface require("pg-search-sequelize").QueryInterface dans vos fonctions up down , construisez une instance et passez à la séquelle queryInterface :
let QueryInterface = require ( "pg-search-sequelize" ) . QueryInterface ;
module . exports = {
up : queryInterface => new QueryInterface ( queryInterface ) . createMaterializedView ( ... ) ,
down : queryInterface => new QueryInterface ( queryInterface ) . dropMaterializedView ( ... ) ,
} ; Crée une nouvelle vue matérialisée dans la base de données qui a deux champs; ID et document. Le champ de document est un ts_vector du texte concaténé de tous les attributs / champs spécifiés pour être consultable
name - le nom de la vue matérialiséemodel - Le modèle du tableau pour créer la vue matérialisée pour.attributes - Objet de paire de valeurs de clé avec la clé étant le nom du champ et la valeur du poids du champ. attributes = {
name : "A" // "A" is the highest weight
description : "B" ,
release_date : "C"
city : "D" // "D" is the lowest possible weight
}options tableName - Si prévu, il remplace le tableName du modèle passé
primaryKeyField - Si prévu, il remplace le primaryKeyField du modèle passé du modèle
include - un tableau d'objets qui définissent les attributs des modèles associés à inclure dans le document de la vue matérialisée.
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 - le modèle à inclureforeignKey - The ForeignKe qui pointe vers le modèle associé. Notez que sur la base du type d'association, la clé étrangère pourrait être sur le modèle de référence (le modèle de film dans l'exemple ci-dessus) ou sur l'autre modèle (le modèle d'acteur).targetKey - La clé que le ForeignKe fait référence.associationType - Le type d'association du point de vue du modèle de référence (film). Ce doit être hasOne , hasMany ou belongsTo .attributes - Les attributs à inclure à partir du modèle.include - un tableau inclut de modèles associés au modèle inclus (ex. Modèles associés à l'acteur) Laisse tomber la vue matérialisée.
name - le nom de la vue matérialisée