mongoose-fuzzy-searching เป็นปลั๊กอินที่เรียบง่ายและมีน้ำหนักเบาซึ่งช่วยให้สามารถค้นหาแบบคลุมเครือในเอกสารใน MongoDB ได้ รหัสนี้อิงจากบทความนี้
ติดตั้งโดยใช้ npm
$ npm i mongoose-fuzzy-searching
หรือใช้เส้นด้าย
$ yarn add mongoose-fuzzy-searching
ก่อนที่จะเริ่มต้น เพื่อแนวทางปฏิบัติที่ดีที่สุดและหลีกเลี่ยงปัญหาใดๆ โปรดจัดการคำเตือนการเลิกใช้งานทั้งหมดอย่างถูกต้อง
เพื่อให้ปลั๊กอินสร้างดัชนี คุณต้องตั้งค่า useCreateIndex
เป็นจริง ตัวอย่างด้านล่างสาธิตวิธีการเชื่อมต่อกับฐานข้อมูล
const options = {
useNewUrlParser : true ,
useUnifiedTopology : true ,
useFindAndModify : false ,
useCreateIndex : true ,
} ;
mongoose . Promise = global . Promise ;
return mongoose . connect ( URL , options ) ;
ในตัวอย่างด้านล่าง เรามีคอลเลกชัน User
และเราต้องการทำการค้นหาแบบคลุมเครือใน firstName
และ lastName
const { Schema } = require ( 'mongoose' ) ;
const mongoose_fuzzy_searching = require ( 'mongoose-fuzzy-searching' ) ;
const UserSchema = new Schema ( {
firstName : String ,
lastName : String ,
email : String ,
age : Number ,
} ) ;
UserSchema . plugin ( mongoose_fuzzy_searching , { fields : [ 'firstName' , 'lastName' ] } ) ;
const User = mongoose . model ( 'User' , UserSchema ) ;
module . exports = { User } ;
const user = new User ( { firstName : 'Joe' , lastName : 'Doe' , email : '[email protected]' , age : 30 } ) ;
try {
await user . save ( ) ; // mongodb: { ..., firstName_fuzzy: [String], lastName_fuzzy: [String] }
const users = await User . fuzzySearch ( 'jo' ) ;
console . log ( users ) ;
// each user object will not contain the fuzzy keys:
// Eg.
// {
// "firstName": "Joe",
// "lastName": "Doe",
// "email": "[email protected]",
// "age": 30,
// "confidenceScore": 34.3 ($text meta score)
// }
} catch ( e ) {
console . error ( e ) ;
}
ผลลัพธ์จะถูกจัดเรียงตามคีย์ confidenceScore
คุณสามารถแทนที่ตัวเลือกนี้ได้
try {
const users = await User . fuzzySearch ( 'jo' ) . sort ( { age : - 1 } ) . exec ( ) ;
console . log ( users ) ;
} catch ( e ) {
console . error ( e ) ;
}
ตัวเลือกสามารถประกอบด้วย fields
และ middlewares
แอตทริบิวต์ Fields มีผลบังคับใช้และควรเป็นอาร์เรย์ของ Strings
หรืออาร์เรย์ของ Objects
หากคุณต้องการใช้ตัวเลือกเริ่มต้นสำหรับฟิลด์ทั้งหมดของคุณ คุณสามารถส่งผ่านเป็นสตริงได้
const mongoose_fuzzy_searching = require ( 'mongoose-fuzzy-searching' ) ;
const UserSchema = new Schema ( {
firstName : String ,
lastName : String ,
email : String ,
} ) ;
UserSchema . plugin ( mongoose_fuzzy_searching , { fields : [ 'firstName' , 'lastName' ] } ) ;
ในกรณีที่คุณต้องการแทนที่ตัวเลือกเริ่มต้นใดๆ สำหรับอาร์กิวเมนต์ของคุณ คุณสามารถเพิ่มตัวเลือกเหล่านี้เป็นออบเจ็กต์และแทนที่ค่าใดๆ ที่คุณต้องการได้ ตารางด้านล่างประกอบด้วยคีย์ที่คาดหวังสำหรับออบเจ็กต์นี้
สำคัญ | พิมพ์ | ค่าเริ่มต้น | คำอธิบาย |
---|---|---|---|
ชื่อ | สตริง | โมฆะ | ชื่อคีย์คอลเลกชัน |
ขนาดขั้นต่ำ | จำนวนเต็ม | 2 | ขนาดต่ำสุด N กรัม เรียนรู้เพิ่มเติมเกี่ยวกับ N-กรัม |
น้ำหนัก | จำนวนเต็ม | 1 | แสดงถึงความสำคัญของฟิลด์ที่สัมพันธ์กับฟิลด์ที่จัดทำดัชนีอื่นๆ ในแง่ของคะแนนการค้นหาข้อความ เรียนรู้เพิ่มเติมเกี่ยวกับน้ำหนักดัชนี |
คำนำหน้าเท่านั้น | บูลีน | เท็จ | คืนค่า ngrams จากจุดเริ่มต้นของคำเท่านั้น (ให้ผลลัพธ์ที่แม่นยำยิ่งขึ้น) |
หลบหนีตัวละครพิเศษ | บูลีน | จริง | ลบอักขระพิเศษออกจาก N-grams |
กุญแจ | อาร์เรย์[สตริง] | โมฆะ | หากประเภทของแอตทริบิวต์การรวบรวมเป็น Object หรือ [Object] (ดูตัวอย่าง) คุณสามารถกำหนดแอตทริบิวต์ที่จะใช้สำหรับการค้นหาแบบคลุมเครือ |
ตัวอย่าง:
const mongoose_fuzzy_searching = require ( 'mongoose-fuzzy-searching' ) ;
const UserSchema = new Schema ( {
firstName : String ,
lastName : String ,
email : String ,
content : {
en : String ,
de : String ,
it : String
}
text : [
{
title : String ,
description : String ,
language : String ,
} ,
] ,
} ) ;
UserSchema . plugin ( mongoose_fuzzy_searching , {
fields : [
{
name : 'firstName' ,
minSize : 2 ,
weight : 5 ,
} ,
{
name : 'lastName' ,
minSize : 3 ,
prefixOnly : true ,
} ,
{
name : 'email' ,
escapeSpecialCharacters : false ,
} ,
{
name : 'content' ,
keys : [ 'en' , 'de' , 'it' ] ,
} ,
{
name : 'text' ,
keys : [ 'title' , 'language' ] ,
} ,
] ,
} ) ;
มิดเดิลแวร์เป็น Object
เสริมที่สามารถมีมิดเดิลแวร์ pre
แบบกำหนดเองได้ ปลั๊กอินนี้ใช้มิดเดิลแวร์เหล่านี้เพื่อสร้างหรืออัปเดตองค์ประกอบที่ไม่ชัดเจน นั่นหมายความว่าหากคุณเพิ่มมิดเดิลแวร์ pre
มิดเดิลแวร์เหล่านั้นจะไม่ถูกเรียกเนื่องจากปลั๊กอินจะแทนที่พวกมัน เพื่อหลีกเลี่ยงปัญหาดังกล่าว คุณสามารถส่งมิดเดิลแวร์ที่คุณกำหนดเองไปยังปลั๊กอินได้ มิดเดิลแวร์ของคุณจะถูกเรียก ก่อน มิดเดิลแวร์ที่คุณสามารถผ่านได้คือ:
schema.pre("save", ...)
schema.pre("insertMany", ...)
schema.pre("update", ...)
schema.pre("updateOne", ...)
schema.pre("findOneAndUpdate", ...)
schema.pre("updateMany", ...)
หากคุณต้องการเพิ่มมิดเดิลแวร์ใดๆ ข้างต้น คุณสามารถเพิ่มลงในปลั๊กอินได้โดยตรง
const mongoose_fuzzy_searching = require ( 'mongoose-fuzzy-searching' ) ;
const UserSchema = new Schema ( {
firstName : String ,
lastName : String ,
} ) ;
UserSchema . plugin ( mongoose_fuzzy_searching , {
fields : [ 'firstName' ] ,
middlewares : {
preSave : function ( ) {
// do something before the object is saved
} ,
} ,
} ) ;
มิดเดิลแวร์สามารถเป็นฟังก์ชันอะซิงโครนัสได้:
const mongoose_fuzzy_searching = require ( 'mongoose-fuzzy-searching' ) ;
const UserSchema = new Schema ( {
firstName : String ,
lastName : String ,
} ) ;
UserSchema . plugin ( mongoose_fuzzy_searching , {
fields : [ 'firstName' ] ,
middlewares : {
preUpdateOne : async function {
// do something before the object is updated (asynchronous)
}
}
} ) ;
คำค้นหาแบบคลุมเครือสามารถใช้เป็นฟังก์ชัน static
หรือเป็น helper
ซึ่งช่วยให้คุณสามารถเชื่อมโยงหลายคำค้นหาเข้าด้วยกัน ชื่อฟังก์ชันในทั้งสองกรณีคือ Surprise, Surprise, fuzzySearch
วิธีการอินสแตนซ์สามารถรับพารามิเตอร์ได้สูงสุดสามตัว รายการแรกคือแบบสอบถามซึ่งอาจเป็นได้ทั้ง String
หรือ Object
จำเป็นต้องมี พารามิเตอร์นี้ พารามิเตอร์ตัวที่สองอาจเป็น Object
ที่มีการสืบค้นเพิ่มเติม (เช่น age: { $gt: 18 }
) หรือฟังก์ชันเรียกกลับ หากพารามิเตอร์ตัวที่สองคือการสืบค้น พารามิเตอร์ตัวที่สามก็คือฟังก์ชันการเรียกกลับ หากคุณไม่ได้ตั้งค่าฟังก์ชันการโทรกลับ ผลลัพธ์จะถูกส่งกลับภายใน Promise
ตารางด้านล่างประกอบด้วยคีย์ที่คาดหวังสำหรับพารามิเตอร์แรก (หากเป็นวัตถุ)
สำคัญ | พิมพ์ | หูหนวก | คำอธิบาย |
---|---|---|---|
แบบสอบถาม | สตริง | โมฆะ | สตริงที่จะค้นหา |
ขนาดขั้นต่ำ | จำนวนเต็ม | 2 | ขนาดต่ำสุด N กรัม |
คำนำหน้าเท่านั้น | บูลีน | เท็จ | คืนค่า ngrams จากจุดเริ่มต้นของคำเท่านั้น (ให้ผลลัพธ์ที่แม่นยำยิ่งขึ้น) คำนำหน้า |
ที่แน่นอน | บูลีน | เท็จ | จับคู่วลี ตรงข้ามกับคำแต่ละคำ |
ตัวอย่าง:
/* With string that returns a Promise */
User . fuzzySearch ( 'jo' ) . then ( console . log ) . catch ( console . error ) ;
/* With additional options that returns a Promise */
User . fuzzySearch ( { query : 'jo' , prefixOnly : true , minSize : 4 } )
. then ( console . log )
. catch ( console . error ) ;
/* With additional queries that returns a Promise */
User . fuzzySearch ( 'jo' , { age : { $gt : 18 } } )
. then ( console . log )
. catch ( console . error ) ;
/* With string and a callback */
User . fuzzySearch ( 'jo' , ( err , doc ) => {
if ( err ) {
console . error ( err ) ;
} else {
console . log ( doc ) ;
}
} ) ;
/* With additional queries and callback */
User . fuzzySearch ( 'jo' , { age : { $gt : 18 } } , ( err , doc ) => {
if ( err ) {
console . error ( err ) ;
} else {
console . log ( doc ) ;
}
} ) ;
คุณยังสามารถใช้ Query เป็นฟังก์ชันตัวช่วยได้ ซึ่งเหมือนกับวิธีการอินสแตนซ์ แต่สำหรับการสืบค้นพังพอน วิธีการช่วยเหลือแบบสอบถามช่วยให้คุณสามารถขยาย API ตัวสร้างแบบสอบถามแบบลูกโซ่ของพังพอนได้
ตัวช่วยสืบค้นสามารถรับพารามิเตอร์ได้สูงสุดสองตัว รายการแรกคือแบบสอบถามซึ่งอาจเป็นได้ทั้ง String
หรือ Object
จำเป็นต้องมี พารามิเตอร์นี้ พารามิเตอร์ตัวที่สองอาจเป็น Object
ที่มีการสืบค้นเพิ่มเติม (เช่น age: { $gt: 18 }
) ซึ่งเป็นทางเลือก ตัวช่วยนี้ไม่ยอมรับฟังก์ชันโทรกลับ หากคุณผ่านฟังก์ชันใดฟังก์ชันหนึ่งจะทำให้เกิดข้อผิดพลาด ข้อมูลเพิ่มเติมเกี่ยวกับตัวช่วยแบบสอบถาม
ตัวอย่าง:
const user = await User . find ( { age : { $gte : 30 } } )
. fuzzySearch ( 'jo' )
. exec ( ) ;
ปลั๊กอินสร้างดัชนีสำหรับฟิลด์ที่เลือก ในตัวอย่างด้านล่าง ดัชนีใหม่จะเป็น firstName_fuzzy
และ lastName_fuzzy
นอกจากนี้ แต่ละเอกสารจะมีฟิลด์ firstName_fuzzy
[String] และ lastName_fuzzy
[String] อาร์เรย์เหล่านี้จะมีแอนนาแกรมสำหรับฟิลด์ที่เลือก
const mongoose_fuzzy_searching = require ( 'mongoose-fuzzy-searching' ) ;
const UserSchema = new Schema ( {
firstName : String ,
lastName : String ,
email : String ,
age : Number ,
} ) ;
UserSchema . plugin ( mongoose_fuzzy_searching , { fields : [ 'firstName' , 'lastName' ] } ) ;
กล่าวอีกนัยหนึ่งปลั๊กอินนี้สร้างแอนนาแกรมเมื่อคุณสร้างหรืออัปเดตเอกสาร เอกสารที่มีอยู่แล้วทั้งหมดจะไม่มีอาร์เรย์ฟัซซี่ ดังนั้นฟังก์ชัน fuzzySearch
จะไม่สามารถค้นหาได้
ในการสร้างแอนนาแกรมสำหรับเอกสารที่มีอยู่แล้ว คุณควรอัปเดตแต่ละเอกสาร ตัวอย่างด้านล่าง อัปเดตแอตทริบิวต์ firstName
ให้กับทุกเอกสารในคอลเลกชัน User
const cursor = Model . find ( ) . cursor ( ) ;
cursor . next ( function ( error , doc ) {
const obj = attrs . reduce ( ( acc , attr ) => ( { ... acc , [ attr ] : doc [ attr ] } ) , { } ) ;
return Model . findByIdAndUpdate ( doc . _id , obj ) ;
} ) ;
ในตัวอย่างก่อนหน้านี้ เราตั้งค่า firstName
และ lastName
เป็นแอตทริบิวต์ที่ไม่ชัดเจน หากคุณลบ firstName
ออกจากฟิลด์แบบคลุมเครือ อาร์เรย์ firstName_fuzzy
จะไม่ถูกลบโดยคอลเลกชัน หากคุณต้องการลบอาร์เรย์ในแต่ละเอกสาร คุณต้องยกเลิกการตั้งค่านั้น
const cursor = Model . find ( ) . cursor ( ) ;
cursor . next ( function ( error , doc ) {
const $unset = attrs . reduce ( ( acc , attr ) => ( { ... acc , [ ` ${ attr } _fuzzy` ] : 1 } ) , { } ) ;
return Model . findByIdAndUpdate ( data . _id , { $unset } , { new : true , strict : false } ) ;
} ) ;
เราใช้เรื่องตลกสำหรับการทดสอบหน่วยและบูรณาการทั้งหมดของเรา
$ npm test
หมายเหตุ: สิ่งนี้จะรันชุดโปรแกรมทั้งหมด ตามลำดับ เพื่อหลีกเลี่ยงการเชื่อมต่อพร้อมกันหลายรายการบน db
ซึ่งจะดำเนินการทดสอบโดยใช้ฐานข้อมูลหน่วยความจำ หากคุณต้องการรันการทดสอบโดยใช้การเชื่อมต่อจริงบนอินสแตนซ์ mongo ไม่ว่าด้วยเหตุผลใดก็ตาม ให้เพิ่มตัวแปรสภาพแวดล้อม MONGO_DB
:
$ docker run --name mongo_fuzzy_test -p 27017:27017 -d mongo
$ MONGO_DB=true npm test
$ npm run test:unit
$ npm run test:integration
ใบอนุญาตเอ็มไอที
ลิขสิทธิ์ (c) 2019 Vassilis Pallas
อนุญาตให้บุคคลใดก็ตามที่ได้รับสำเนาของซอฟต์แวร์นี้และไฟล์เอกสารที่เกี่ยวข้อง ("ซอฟต์แวร์") อนุญาตโดยไม่เสียค่าใช้จ่าย เพื่อจัดการกับซอฟต์แวร์โดยไม่มีข้อจำกัด รวมถึงแต่ไม่จำกัดเพียงสิทธิ์ในการใช้ คัดลอก ปรับเปลี่ยน ผสาน เผยแพร่ แจกจ่าย ให้อนุญาตช่วง และ/หรือขายสำเนาของซอฟต์แวร์ และอนุญาตให้บุคคลที่ได้รับซอฟต์แวร์นี้สามารถทำได้ ภายใต้เงื่อนไขต่อไปนี้:
ประกาศเกี่ยวกับลิขสิทธิ์ข้างต้นและประกาศการอนุญาตนี้จะรวมอยู่ในสำเนาทั้งหมดหรือส่วนสำคัญของซอฟต์แวร์
ซอฟต์แวร์นี้มีให้ "ตามที่เป็น" โดยไม่มีการรับประกันใดๆ ทั้งโดยชัดแจ้งหรือโดยนัย ซึ่งรวมถึงแต่ไม่จำกัดเพียงการรับประกันความสามารถในการค้าขาย ความเหมาะสมสำหรับวัตถุประสงค์เฉพาะ และการไม่ละเมิด ไม่ว่าในกรณีใดผู้เขียนหรือผู้ถือลิขสิทธิ์จะต้องรับผิดต่อการเรียกร้องค่าเสียหายหรือความรับผิดอื่นใดไม่ว่าในการกระทำของสัญญาการละเมิดหรืออย่างอื่นที่เกิดขึ้นจากหรือเกี่ยวข้องกับซอฟต์แวร์หรือการใช้งานหรือข้อตกลงอื่น ๆ ใน ซอฟต์แวร์.