In questo articolo vedremo come implementare un motore di ricerca con Node.js e MongoDB.
MySQL: stopwords, LIKE, AND e OR
WordPress implementa il suo motore di ricerca come segue:
- valida la query string
- crea un array di parole dalla query string
- rimuove le stopwords dall'array
- usa
LIKE
conAND
/OR
sul titolo, sul riassunto e sul contenuto dei post.
MongoDB: $text e $regex
Se usiamo $text
dobbiamo creare degli indici:
db.posts.createIndex({title: "text"});
db.posts.createIndex({content: "text"});
db.posts.createIndex({excerpt: "text"});
Quindi:
db.posts.find({'$and': [{'title': {'$text': 'query'}}, {'content': {'$text': 'query'}}, {'excerpt': {'$text': 'query'}}]});
Dato che $text
non usa le espressioni regolari, query
e Query
sono due termini diversi.
La corrispondenza in questo caso è esatta, quindi per ottenere più risultati dobbiamo usare $regex
con l'opzione i
:
db.posts.find({'$and': [{'title': {'$regex': 'query', '$options': 'i'}}, {'content': {'$regex': 'query', '$options': 'i'}}, {'excerpt': {'$regex': 'query', '$options': 'i'}}]});
L'implementazione
In Node.js possiamo scrivere:
'use strict';
const stopwords = require('./src/stopwords'); // Array di stopwords
const Docs = require('./src/db/Docs');
const app = require('express')();
let queryVar = function(str) {
let q = str.replace( /\r\n/g, '').replace(/^\s+|\s+$/, '').replace(/[^a-z\s]+/gi, '').replace(/\s+$/, '');
let parts = q.split(/\s/);
let terms = [];
parts.forEach(part => {
if(stopwords.indexOf(part) === -1) {
terms.push(part);
}
});
let query = {'$and': []};
terms.forEach(term => {
let queryFrag = {title: {'$regex': term, '$options': 'i'}};
query['$and'].push(queryFrag);
});
return query;
};
app.get('/search', (req, res) => {
let searchQuery = queryVar(req.query.term);
Docs.find(searchQuery).then(results => {
//...
}).catch(err => {
//...
});
});
app.listen(3000);