อย่าลังเลที่จะคว้ารหัสใด ๆ ที่คุณพบว่ามีประโยชน์ หรือดีกว่ายังคุณมากกว่าที่จะเป็นผู้ดูแล! คำขอโทษอย่างจริงใจที่ลึกที่สุดของฉันที่ปล่อยให้โครงการนี้ดำเนินต่อไป ฉันหวังว่ามันจะไม่ทำให้คุณไม่สะดวก
Postgres การค้นหาข้อความแบบเต็มใน node.js โดยใช้ลำดับเป็น ORM
ตรวจสอบตัวอย่างรหัส
ไลบรารีนี้ใช้ประโยชน์จากการค้นหาข้อความแบบเต็มรูปแบบและมุมมองที่เป็นรูปธรรมเพื่อเรียกใช้การค้นหาที่รวดเร็วทรงพลังและเรียบง่าย ครั้งแรกมันสร้างมุมมองที่เป็นรูปธรรมโดยการเชื่อมต่อค่าทั้งหมดในฟิลด์ที่คุณต้องการทำให้สามารถค้นหาได้และแปลงเป็น ts_vector จากนั้นจะเพิ่มเมธอด searchByText และ search ในรูปแบบภาคต่อของคุณซึ่งช่วยให้คุณเรียกใช้การค้นหาจากสตริงแบบสอบถามเท่านั้นหรือสตริงแบบสอบถามและตัวเลือกวัตถุ JSON นอกจากนี้ยังเพิ่มวิธี refresh คลาสเพื่อรีเฟรชมุมมองที่เป็นรูปธรรมเมื่อมีการอัปเดตกับโมเดลของคุณหรือเมื่อใดก็ตามที่คุณต้องการ
ตัวอย่างเช่นสมมติว่าเรามีตารางฐานข้อมูลภาพยนตร์ที่มี:
| รหัสประจำตัว | ชื่อ | คำอธิบาย | เมือง | release_date | การให้คะแนน |
|---|---|---|---|---|---|
| 1 | ผู้ลี้ภัย | ผู้ชายอีกคนหนีออกจากคุก | ชิคาโก | 1993-08-06 | 8 |
| 2 | จิตใจที่สวยงาม | ภาพยนตร์เกี่ยวกับนักคณิตศาสตร์ | นิวยอร์ก | 2001-12-05 | 8 |
| 3 | ชิคาโก | ละครเพลงอเมริกันที่ดี | โตรอนโต | 2002-12-10 | 7 |
| 4 | แสงแดดนิรันดร์ของจิตใจไร้ที่ติ | Jim Carrey เมื่อเขาไม่ใช่นักแสดงตลก | นิวยอร์ก | 2004-03-19 | 8 |
เราต้องการอนุญาตให้ค้นหาตามชื่อคำอธิบายและเมืองและการกรองโดยการให้คะแนนและ release_date นอกจากนี้เรายังต้องการเรียงลำดับผลลัพธ์ด้วยความเกี่ยวข้องโดยให้น้ำหนักมีน้ำหนักสูงกว่าคำอธิบายและเมือง ดังนั้นหากคุณเรียกใช้การค้นหา:
Film . searchByText ( "Chicago" ) ; // Returns [ Chicago, The Fugitive ]ผลลัพธ์ด้วยคำว่า "ชิคาโก" ในชื่อปรากฏต่อหน้าผู้ที่มีคำเดียวกันในคำอธิบายหรือเมือง ดังนั้นภาพยนตร์ชิคาโกจะปรากฏขึ้นก่อนและผู้ลี้ภัยจะเป็นครั้งที่สอง
นอกจากนี้เรายังสามารถเพิ่มการกรองและการสั่งซื้อโดยฟิลด์บางอย่างแทนที่จะสั่งซื้อตามความเกี่ยวข้องโดยการทำคำค้นหา:
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 ]คุณไม่ได้ จำกัด เฉพาะฟิลด์ของรุ่นเดียวเท่านั้น คุณสามารถรวมฟิลด์จากโมเดลที่เกี่ยวข้องได้เช่นกัน ตัวอย่างเช่นหากเรามีรูปแบบอื่นในฐานข้อมูลของเราที่เรียกว่านักแสดงซึ่งเกี่ยวข้องกับภาพยนตร์โดยคีย์ต่างประเทศเราสามารถรวมฟิลด์จากโมเดลนักแสดงที่จะอยู่ในมุมมองภาพยนตร์ สิ่งนี้ช่วยให้เราสามารถเรียกใช้การค้นหาเช่น:
Film . searchByText ( "Tom Hanks" ) ; // Returns Tom Hanks moviesมีอีกมากที่คุณสามารถทำได้กับห้องสมุดนี้ สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับวิธีการติดตั้งและใช้ให้ตรวจสอบส่วนการติดตั้งและการใช้งาน สำหรับเอกสารตรวจสอบส่วนเอกสาร
NPM ติดตั้งแพ็คเกจ pg-search-sequelize
npm i --save pg-search-sequelizeจากนั้นต้องการมันในไฟล์นิยามโมเดลมุมมองที่เป็นรูปธรรมของคุณและส่งต่อไปยังรุ่นต่อเนื่องเพื่อให้สามารถค้นหาได้:
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.โปรดดูการใช้งานสำหรับวิธีการกำหนดโมเดลของคุณและวิธีการสร้างมุมมองที่เป็นรูปธรรม
ตอนนี้คุณได้แอบดูสิ่งที่ห้องสมุดนี้ช่วยให้คุณได้ในตอนท้ายมาถึงขั้นตอนการตั้งค่า:
หากคุณใช้เครื่องมือการอพยพตามลำดับคุณสามารถใช้ createMaterializedView(name, referenceModel, attributes, options) ฟังก์ชั่นตัวช่วยที่จัดทำโดยคลาส 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 )
}หากคุณไม่ได้ใช้เครื่องมือการโยกย้ายตามลำดับคุณสามารถสร้างมุมมองที่เป็นรูปธรรมไม่ว่าคุณจะต้องการอะไรก็ตาม
กำหนดรูปแบบของมุมมองที่เป็นรูปธรรมของคุณในลักษณะเดียวกับที่คุณกำหนดรูปแบบภาคต่ออื่น ๆ ความแตกต่างเพียงอย่างเดียวคือคุณต้องเพิ่มคุณสมบัติ referenceModel ลงในตัวเลือกคำจำกัดความโมเดลของคุณ จากนั้นเพียงแค่สร้างโมเดล SearchModel จากรูปแบบมุมมองที่เป็นรูปธรรมที่คุณเพิ่งกำหนด
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. ตอนนี้คุณสามารถโทรหา materializedViewModel.search(query, options) หรือ materializedViewModel.searchByText(query) เพื่อเรียกใช้การค้นหาข้อความแบบเต็มในโมเดลและการเชื่อมโยงของคุณ
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" ] ]
}อย่าลืมรีเฟรชมุมมองที่เป็นรูปธรรมเพื่ออัปเดตด้วยการเปลี่ยนแปลงล่าสุดที่เกิดขึ้นกับโมเดลของคุณ วิธีหนึ่งในการทำเช่นนั้นคือการสร้าง Aftercreate, AfterUpdate และ AfterDelete Hook บนโมเดลของคุณเพื่อรีเฟรชมุมมองที่เป็นรูปธรรม:
sequelize . define ( 'Film' , attributes , {
hooks : {
afterCreate : ( ) => FilmMaterializedView . refresh ( ) ,
afterUpdate : ( ) => FilmMaterializedView . refresh ( ) ,
afterDelete : ( ) => FilmMaterializedView . refresh ( )
}
} ) ;หรือคุณสามารถมีตัวกำหนดตารางงานที่รีเฟรชมุมมองที่เป็นรูปธรรมของคุณทุกระยะเวลา x
มุ่งหน้าไปยังส่วนเอกสารเพื่อเรียนรู้เกี่ยวกับการค้นหาประเภทใดที่คุณสามารถทำได้
PG Search - Sequelize มี 2 คลาสคือ SearchModel และ QueryInterface
คลาส SearchModel เป็นสิ่งที่คุณใช้เพื่อเพิ่มวิธีการค้นหาและรีเฟรชคลาสในรูปแบบมุมมองที่เป็นรูปธรรมของคุณ ในการเข้าถึงคลาส SearchModel require("pg-search-sequelize") ฟังก์ชั่นต่อไปนี้สามารถเรียกได้จากโมเดลที่คุณสร้างด้วยคลาส SearchModel MyModel = new SearchModel(MyModel)
ค้นหาโมเดลมุมมองที่เป็นรูปธรรมโดยใช้สตริงการค้นหาและวัตถุตัวเลือก
query - สตริงการค้นหาoptionswhere - กรองเพื่อ จำกัด ผลลัพธ์โดย /*
Format:
options.where = {
attribute: {
operator: ">, <, =, >=, <=, @@, ilike, etc.",
value: "some value"
}
*/
// Example:
options . where = {
releaseDate : {
operator : ">" ,
value : "2012-01-01"
}
}attributes - อาร์เรย์ของคุณลักษณะที่จะส่งคืน อดีต. options . attributes = [ "name" , "releaseDate" , "rating" ]order - อาร์เรย์ของอาร์เรย์ที่มีค่าแรกเป็นชื่อแอตทริบิวต์และที่สองคือทิศทาง ตัวอย่างเช่น: options . order = [
[ "name" , "ASC" ] ,
[ "releaseDate" , "DESC" ] ,
[ "rating" , "DESC" ]
] Promise - อาร์เรย์ของอินสแตนซ์ผลการค้นหาที่มีแอตทริบิวต์ที่ระบุไว้ในวัตถุตัวเลือก, defaultScope ของโมเดลมุมมองที่เป็นรูปธรรมหรือแอตทริบิวต์ทั้งหมดในคำจำกัดความของโมเดลมุมมองที่เป็นรูปธรรม
ค้นหารูปแบบมุมมองที่เป็นรูปธรรมด้วยแบบสอบถามข้อความเท่านั้น สิ่งนี้มีประโยชน์อย่างยิ่งสำหรับการเปิดเผยจุดสิ้นสุดการค้นหา API ไปยังโมเดลของคุณดังนั้นคุณไม่ต้องกังวลเกี่ยวกับการแยกวิเคราะห์สตริงการค้นหา
query - สตริงของข้อความค้นหาตัวกรองและฟิลด์เพื่อสั่งซื้อโดย // --------------
// 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 - อาร์เรย์ของอินสแตนซ์ผลการค้นหาที่มีแอตทริบิวต์ defaultScope ของโมเดลมุมมองที่เป็นรูปธรรมหรือแอตทริบิวต์ทั้งหมดในคำจำกัดความของโมเดลมุมมองที่เป็นรูปธรรม
รีเฟรชมุมมองที่เป็นรูปธรรม อดีต. models.Film.afterCreate(() => MaterializedViews.Film.refresh())
คลาส QueryInterface นั้นมีไว้สำหรับการโยกย้าย เช่นการสร้างและลดมุมมองที่เป็นรูปธรรม ในการเข้าถึงคลาส QueryInterface require("pg-search-sequelize").QueryInterface ในฟังก์ชั่น up และ down ของคุณสร้างอินสแตนซ์และส่งต่อไปยัง Sequelize queryInterface :
let QueryInterface = require ( "pg-search-sequelize" ) . QueryInterface ;
module . exports = {
up : queryInterface => new QueryInterface ( queryInterface ) . createMaterializedView ( ... ) ,
down : queryInterface => new QueryInterface ( queryInterface ) . dropMaterializedView ( ... ) ,
} ; สร้างมุมมองที่เป็นรูปธรรมใหม่ในฐานข้อมูลที่มีสองฟิลด์ ID และเอกสาร ฟิลด์เอกสารเป็น ts_vector ของข้อความที่ต่อกันของแอตทริบิวต์/ฟิลด์ที่ระบุทั้งหมดที่จะค้นหาได้
name - ชื่อมุมมองที่เป็นรูปธรรมmodel - โมเดลของตารางเพื่อสร้างมุมมองที่เป็นรูปธรรมสำหรับattributes - วัตถุคู่คีย์ - ค่าที่มีคีย์เป็นชื่อของฟิลด์และค่าน้ำหนักของฟิลด์ attributes = {
name : "A" // "A" is the highest weight
description : "B" ,
release_date : "C"
city : "D" // "D" is the lowest possible weight
}options tableName - หากมีให้มันจะแทนที่ tableName ของรุ่นที่ผ่าน
primaryKeyField - หากมีให้มันจะแทนที่ primaryKeyField ของโมเดลที่ผ่าน
include - อาร์เรย์ของวัตถุที่กำหนดคุณลักษณะของโมเดลที่เกี่ยวข้องเพื่อรวมไว้ในเอกสารของมุมมองที่เป็นรูปธรรม
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 - โมเดลที่จะรวมforeignKey - คนต่างชาติที่ชี้ไปที่โมเดลที่เกี่ยวข้อง โปรดทราบว่าขึ้นอยู่กับประเภทการเชื่อมโยงคีย์ต่างประเทศอาจอยู่ในรูปแบบการอ้างอิง (โมเดลภาพยนตร์ในตัวอย่างด้านบน) หรือในรุ่นอื่น ๆ (โมเดลนักแสดง)targetKey - กุญแจสำคัญที่การอ้างอิงของต่างชาติassociationType - ประเภทการเชื่อมโยงจากมุมมองของโมเดลอ้างอิง (ฟิล์ม) มันจะต้องเป็น hasOne , hasMany หรือ belongsToattributes - คุณลักษณะที่จะรวมจากโมเดลinclude - รวมอาร์เรย์ของโมเดลที่เกี่ยวข้องกับโมเดลที่รวมอยู่ (แบบจำลองที่เกี่ยวข้องกับนักแสดง) ลดมุมมองที่เป็นรูปธรรม
name - ชื่อมุมมองที่เป็นรูปธรรม