Sinta -se à vontade para pegar qualquer código de código que você achar útil. Ou melhor ainda, você é mais do que bem -vindo para se tornar um mantenedor! Minhas mais profundas sinceras desculpas por deixar este projeto ir. Espero que não te causa inconveniência.
Postgres de texto completo Pesquisa no Node.js usando sequelizar como seu ORM.
Confira o exemplo do código.
Esta biblioteca utiliza a pesquisa de texto completo do Postgres e as visualizações materializadas para executar consultas de pesquisa rápidas, poderosas e simples. Primeiro, ele cria uma visão materializada concatenando todos os valores nos campos que você deseja transformar e os converte em um ts_vector . Em seguida, adiciona um Métodos de classe searchByText e search ao seu modelo sequeleizado, o que permite executar pesquisas apenas a partir de uma sequência de consultas ou de uma sequência de consulta e um objeto JSON Options. Ele também adiciona um método de classe de refresh para atualizar a visualização materializada quando as atualizações são feitas no seu modelo ou quando você quiser.
Por exemplo, vamos supor que temos uma tabela de banco de dados de filmes que possui:
| eu ia | nome | descrição | cidade | release_date | avaliação |
|---|---|---|---|---|---|
| 1 | O fugitivo | Outro cara escapa da prisão | Chicago | 1993-08-06 | 8 |
| 2 | Uma bela mente | Um filme sobre um matemático | Nova Iorque | 2001-12-05 | 8 |
| 3 | Chicago | Um bom e velho musical americano | Toronto | 2002-12-10 | 7 |
| 4 | Sol eterno da mente impecável | Jim Carrey quando ele não é comediante | Nova Iorque | 2004-03-19 | 8 |
Queremos permitir a pesquisa por nome, descrição e cidade e filtragem por classificação e release_date. Também queremos classificar os resultados relevantes, dando ao campo o nome de um peso mais alto que a descrição e a cidade. Então, se você executar a pesquisa:
Film . searchByText ( "Chicago" ) ; // Returns [ Chicago, The Fugitive ]Os resultados com a palavra "Chicago" no título aparecem antes daqueles com a mesma palavra na descrição ou cidade. Assim, o filme Chicago apareceria primeiro, e o fugitivo seria o segundo.
Também podemos adicionar filtragem e pedido em um determinado campo, em vez de ordenar relevância, fazendo a consulta de pesquisa:
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 ]Você também não se limita apenas aos campos de um modelo; Você também pode incluir campos de modelos associados. Por exemplo, se tivéssemos outro modelo em nosso banco de dados chamado ator associado ao filme por uma chave estrangeira, podemos incluir campos do modelo de ator para estar na visão materializada do filme. Isso nos permite executar pesquisas como:
Film . searchByText ( "Tom Hanks" ) ; // Returns Tom Hanks moviesHá mais que você pode fazer com esta biblioteca. Para mais detalhes sobre como instalá -lo e usá -lo, consulte as seções de instalação e uso. Para documentação, consulte a seção de documentação.
NPM Instale o pacote pg-search-sequelize
npm i --save pg-search-sequelizeEm seguida, exija -o no seu arquivo de definição de modelo de visualização materializado e passe para ele o modelo de sequência para torná -lo pesquisável:
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.Consulte o uso de como definir seu modelo e como criar a visão materializada.
Agora que você teve uma prévia do que essa biblioteca permite no final, vamos às etapas de configuração:
Se você usar a Ferramenta de Migrações Sequelizadas, poderá usar a função Helper createMaterializedView(name, referenceModel, attributes, options) fornecida pela 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 )
}Se você não usar a ferramenta de migração de sequelização, sinta -se à vontade para criar a visão materializada da maneira que preferir.
Defina o modelo da sua visão materializada da mesma maneira que você define quaisquer outros modelos de sequeLizar. A única diferença é que você precisa adicionar a propriedade referenceModel às suas opções de definição de modelo. Em seguida, basta construir um SearchModel a partir do modelo de visão materializado que você acabou de definir.
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. Agora você pode ligar para materializedViewModel.search(query, options) ou materializedViewModel.searchByText(query) para executar uma pesquisa de texto completo em seu modelo e suas associações.
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ão se esqueça de atualizar a visão materializada para atualizá -la com as últimas alterações feitas no seu modelo. Uma maneira de fazer isso é criar um gancho AfterCree, AfterUpdate e AfterDelete em seu modelo para atualizar a visão materializada:
sequelize . define ( 'Film' , attributes , {
hooks : {
afterCreate : ( ) => FilmMaterializedView . refresh ( ) ,
afterUpdate : ( ) => FilmMaterializedView . refresh ( ) ,
afterDelete : ( ) => FilmMaterializedView . refresh ( )
}
} ) ;Como alternativa, você pode ter um agendador de empregos que atualize sua visão materializada a cada tempo X.
Vá para a seção de documentação para saber sobre que tipo de pesquisa você pode fazer.
PG Pesquisa - Sequelize possui 2 classes, SearchModel e QueryInterface .
A classe SearchModel é o que você usaria para adicionar os métodos de classe de pesquisa e atualização ao seu modelo de sequelização de visualização materializada. Para acessar a classe SearchModel require("pg-search-sequelize") . As seguintes funções podem ser chamadas do modelo que você constrói com a classe de pesquisa MyModel = new SearchModel(MyModel)
Pesquise o modelo de exibição materializado usando uma string de consulta de pesquisa e um objeto de opções.
query - a sequência de consulta de pesquisa.optionswhere - filtra para limitar os resultados por. /*
Format:
options.where = {
attribute: {
operator: ">, <, =, >=, <=, @@, ilike, etc.",
value: "some value"
}
*/
// Example:
options . where = {
releaseDate : {
operator : ">" ,
value : "2012-01-01"
}
}attributes - Uma matriz dos atributos para retornar. ex. options . attributes = [ "name" , "releaseDate" , "rating" ]order - Uma matriz de matrizes com o primeiro valor sendo o nome do atributo e o segundo sendo a direção. Por exemplo: options . order = [
[ "name" , "ASC" ] ,
[ "releaseDate" , "DESC" ] ,
[ "rating" , "DESC" ]
] Promise - Uma matriz das instâncias de resultados de pesquisa com os atributos especificados no objeto Opções, o defaultScope do modelo de visão materializado ou todos os atributos na definição do modelo de visão materializada.
Pesquise o modelo de visão materializado apenas com uma consulta de texto. Isso é especialmente útil para expor um endpoint da API de pesquisa ao seu modelo, para que você não precise se preocupar em analisar a sequência de consultas de pesquisa.
query - Uma string do texto de consulta, filtros e campo para encomendar por. // --------------
// 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 - Uma matriz das instâncias dos resultados da pesquisa com os atributos defaultScope do modelo de visão materializado ou todos os atributos na definição de modelo de visão materializada.
Atualize a visão materializada. ex. models.Film.afterCreate(() => MaterializedViews.Film.refresh())
A classe QueryInterface é destinada a executar migrações; ou seja, criando e soltando a visão materializada. Para acessar a classe QueryInterface require("pg-search-sequelize").QueryInterface nas suas funções up e down , construa uma instância e passa para ele a sequelize queryInterface :
let QueryInterface = require ( "pg-search-sequelize" ) . QueryInterface ;
module . exports = {
up : queryInterface => new QueryInterface ( queryInterface ) . createMaterializedView ( ... ) ,
down : queryInterface => new QueryInterface ( queryInterface ) . dropMaterializedView ( ... ) ,
} ; Cria uma nova visão materializada no banco de dados que possui dois campos; ID e documento. O campo do documento é um ts_vector do texto concatenado de todos os atributos/campos especificados a serem pesquisáveis
name - o nome da visão materializadamodel - O modelo da tabela para criar a visão materializada para.attributes - Objeto do par de valores -chave, com a chave sendo o nome do campo e o valor do peso do campo. attributes = {
name : "A" // "A" is the highest weight
description : "B" ,
release_date : "C"
city : "D" // "D" is the lowest possible weight
}options tableName - Se fornecido, substitui o nome do tableName do modelo
primaryKeyField - se fornecido, substitui o primaryKeyField do modelo aprovado
include - uma variedade de objetos que definem os atributos dos modelos associados a serem incluídos no documento da visão materializada.
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 - o modelo a incluirforeignKey - o ForeignKey que aponta para o modelo associado. Observe que, com base no tipo de associação, a chave estranha pode estar no modelo de referência (o modelo de filme no exemplo acima) ou no outro modelo (o modelo do ator).targetKey - A chave que o ForeignKey Referências.associationType - o tipo de associação da perspectiva do modelo de referência (filme). Deve ser hasOne , hasMany ou belongsTo .attributes - Os atributos a serem incluídos no modelo.include - uma matriz incluída de modelos associados ao modelo incluído (por exemplo, modelos associados ao ator) Solta a visão materializada.
name - o nome da visão materializada