2016-02-02 21 views
6

こんにちは、私は私のコレクションで人物を検索するためにマングースを使用しています。マングースのテキスト検索

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

は、今私は、クエリを持つ人を探したい:

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

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

(私はジョーを検索する場合、イベントを)私は結果を得るジョンのために私が検索した場合。 しかし、私は明らかに任意の結果を得ていないのですジョン・ドウを検索する場合。

私はジョンQUERYを変更した場合|ドウ私は結果を得るが、それは彼らの直前に入っ/ファーストネームでジョンまたはドウを持っているいずれかの人員を返します。

次のことは、マングースのTEXTSEARCHで試してみた:

まず、インデックスにフィールドを追加します。

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

そして、人のクエリを変更:

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

これはうまく動作します!全体初段/姓と一致しかし、今では唯一返している人数:

- 方法はあります>ジョーは値を返しません

- ジョン戻り

を大切>これを解決するには?

アンサー外部プラグインなしが優先されますが、他の人も同様です。

+0

これにはElasticsearchを使用する必要があります。私は、あなたが好きなら詳細なコードを提供することができます。フルネーム検索を行うには、クエリを\ "query" \ formatに置く必要があります。 –

+0

マングースのみで部分検索を行っても機能しません。私は3日間弾力をつけることを選ぶ前に試みました。 –

+0

あなたに感謝しますが、Elastiqはこのケースではあまりにも多すぎるようです。姓と名を1つのフィールドにマージする可能性がある場合(1つのクエリのみ)、正規表現で検索してください。しかし、私はマングースがそれをすることができるかどうか分からないのですか? – Carsten

答えて

5

あなたは$concatを使用して一緒に姓と名を連結し、そのに対して検索aggregateパイプラインでこれを行うことができます。これは、インデックスを使用できないよう

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); 
}); 

パフォーマンスは、しかし、懸念されますそれは完全なコレクションスキャンが必要になります。

あなたはパイプラインの残りの部分は見てする必要があるドキュメントのセットを減らすためにインデックスを使用できることを$matchクエリで$projectステージに先行することによってそのを緩和することができます。

ですから、別にインデックスname.first、その後name.lastとはアンカークエリとして検索文字列の最初の単語を取る場合(例えば、/^John/i)、あなたはパイプラインの先頭に以下を付加できます。

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

明らかにあなたはprogrammicaticallyその「最初の単語」正規表現を生成する必要があると思いますが、うまくいけば、それはあなたのアイデアを提供します。

1

正規表現でこれを手伝うことができます。

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