2016-02-02 57 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); 
}); 

如果我搜索約翰我得到的結果(事件,如果我搜索)。 但如果我搜索John Doe我沒有得到任何結果。

如果我改變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。如果你喜歡,我可以爲你提供詳細的代碼。爲了獲得全名搜索,你應該把查詢放在\「查詢」\格式中。 –

+0

僅使用貓鼬進行部分搜索不起作用。我嘗試了3天,然後選擇彈性。 –

+0

謝謝你的提示,但對於這種情況,Elastiq似乎有點太過分了。如果有可能將首字母和姓氏合併成一個字段(僅用於一個查詢),然後用正則表達式進行搜索就可以完成。但我不確定貓鼬是否可以做到這一點? – Carsten

回答

5

您可以用aggregate流水線串接的名字和姓氏使用$concat在一起,然後做搜索針對:

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

性能是一個問題,但是,因爲這不能使用索引所以它需要完整的收集掃描。

您可以通過$project階段之前有$match查詢可以使用索引來降低設定文檔的其餘管道需要看減輕。

因此,如果您單獨索引name.firstname.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) { 
});