2016-02-02 22 views
6

Hallo ich benutze mongoose um nach Personen in meiner Sammlung zu suchen.Mungo-Textsuche mit Teilstring

/*Person model*/ 
{ 
    name: { 
     first: String, 
     last: String 
    } 
} 

Jetzt möchte ich für Personen mit einer Abfrage suchen:

let regex = new RegExp(QUERY,'i'); 

Person.find({ 
    $or: [ 
     {'name.first': regex}, 
     {'name.last': regex} 
    ] 
}).exec(function(err,persons){ 
    console.log(persons); 
}); 

Wenn ich für suchen John i Ergebnisse erhalten (event, wenn ich für Jo suchen). Aber wenn ich nach John Doe suche, bekomme ich offensichtlich keine Ergebnisse.

Wenn ich QUERY zu John ändern | Doe i Ergebnisse zu erhalten, aber es gibt alle Personen, die entweder John oder Doe in ihrer letzt/Vornamen haben.

Das nächste, was war mit Mungo TEXTSUCHE, um zu versuchen:

Erste Felder hinzufügen zu indizieren:

PersonSchema.index({ 
    name: { 
     first: 'text', 
     last: 'text' 
    } 
},{ 
    name: 'Personsearch index', 
    weights: { 
     name: { 
      first : 10, 
      last: 10 
    } 
} 
}); 

Dann ändern Sie die Person query:

Person.find({ 
    $text : { 
     $search : QUERY 
    } 
}, 
{ score:{$meta:'textScore'} }) 
.sort({ score : { $meta : 'textScore' } }) 
.exec(function(err,persons){ 
    console.log(persons); 
}); 

Dies funktioniert gut! Aber jetzt ist es nur wiederkehrende Personen, die mit dem ganzen Vor-/Nachname entsprechen:

->John kehrt Wert

->Jo kehrt kein Wert

Gibt es eine Möglichkeit um das zu lösen?

Antworten ohne externe Plugins sind bevorzugt, aber andere sind auch gewünscht.

+0

Möglicherweise müssen Sie Elasticsearch dafür verwenden. Ich kann Ihnen einen detaillierten Code zur Verfügung stellen, wenn Sie möchten. Um die vollständige Namenssuche zu erhalten, sollten Sie die Abfrage im \ "query \ format \" ablegen. –

+0

Eine Teilsuche mit nur Mungo funktioniert nicht. Ich habe es 3 Tage lang versucht, bevor ich mich für Elastic entschieden habe. –

+0

Danke für den Hinweis, aber Elastiq scheint für diesen Fall ein bisschen zu viel zu sein. Wenn es eine Möglichkeit gäbe, den Vor- und Nachnamen in ein Feld zusammenzufassen (nur für eine Abfrage) und dann mit regex zu suchen, würde es dies tun. Aber ich bin mir nicht sicher, ob Mungo das kann? – Carsten

Antwort

5

Sie können dies tun mit einer aggregate Pipeline, die die Vor- und Nachnamen verkettet zusammen $concat mit und sucht dann gegen das:

let regex = new RegExp(QUERY,'i'); 

Person.aggregate([ 
    // Project the concatenated full name along with the original doc 
    {$project: {fullname: {$concat: ['$name.first', ' ', '$name.last']}, doc: '$$ROOT'}}, 
    {$match: {fullname: regex}} 
], function(err, persons) { 
    // Extract the original doc from each item 
    persons = persons.map(function(item) { return item.doc; }); 
    console.log(persons); 
}); 

Leistung ein Anliegen ist jedoch, da dies nicht einen Index verwenden können Daher wird ein vollständiger Sammlungs-Scan benötigt.

Sie können das mit einem $match Abfrage vor der $project Stufe mildern, dass einen Index verwenden können, um den Satz von docs der Rest der Pipeline betrachten muss zu reduzieren.

Wenn Sie also name.first und name.last separat indexieren und dann das erste Wort Ihrer Suchzeichenfolge als verankerte Abfrage verwenden (z.

{$match: $or: [ 
    {'name.first': /^John/i}, 
    {'name.last': /^John/i} 
]} 

Offensichtlich Sie brauchen würde, um programmicatically zu erzeugen, dass „erste Wort“ regex, aber es gibt Ihnen hoffentlich die Idee: /^John/i), könnten Sie folgendes an den Anfang Ihrer Pipeline voranstellen.

1

Regex kann Ihnen dabei helfen.

Person.find({ "name": { "$regex": "Alex", "$options": "i" } }, 
function(err,docs) { 
});