sql >> Databasteknik >  >> NoSQL >> MongoDB

Mongoose - Sök efter text i tre fält baserat på poäng eller vikt

Ett "textindex" och sök är sannolikt det bästa alternativet här så länge du söker efter hela ord.

Att lägga till ett textindex till din schemadefinition är ganska enkelt:

BookSchema.index(
    {
         "name": "text",
         "description": "text",
         "body": "text"
    },
    {
        "weights": {
            "name": 5,
            "description": 2
        }
    }
)

Detta gör att du kan utföra enkla sökningar med "ställ in" viktning av fälten:

Book.find({ "$text": { "$search": "Holiday School Year" } })
    .select({ "score": { "$meta": "textScore" } })
    .sort({ "score": { "$meta": "textScore" } })
    .exec(function(err,result) {

    }
);

Där varje term som matchas kommer att betraktas mot det fält den hittades i som ger mest vikt och antalet förekomster.

Att tilldela vikterna är kopplat till "indexet", så definitionen görs en gång och kan inte ändras. En annan begränsning är att vid "textsökning" inte tittar på "delvisa" ord. Till exempel "ci" matchar inte "Stad" eller "Medborgare", och för en sådan sak skulle du behöva ett reguljärt uttryck istället.

Om du behövde mer flexibilitet än så eller generellt måste kunna ändra viktningen av resultat dynamiskt, behöver du något som aggregationsramverket eller mapReduce.

Aggregeringsramverket kan dock inte utföra en "logisk" matchning operation (den kan filtrera genom $match operator, men inte en "logisk" matchning ) av ett "reguljärt uttryck" till dina termer. Du kan dock arbeta med enstaka ord och "exakta" matchningar om det passar.

Book.aggregate(
    [
        { "$match": {
            "$or": [
                { "name": /Holiday/ },
                { "description": /Holiday/ },
                { "body": /Holiday/ }
            ]
        }},
        { "$project": {
            "name": 1,
            "description": 1,
            "body": 1,
            "score": {
                "$add": [
                    { "$cond": [{ "$eq": [ "$name", "Holiday" ] },5,0 ] },
                    { "$cond": [{ "$eq": [ "$description", "Holiday" ] },2,0 ] },
                    { "$cond": [{ "$eq": [ "$body", "Holiday" ] },1,0 ] }
                ]
            }
        }},
        { "$sort": { "score": -1 } }
    ],
    function(err,results) {

    }
)

Som en aggregeringspipeline använder man en datastruktur för att fråga där du kan ändra parametrarna för vikt för varje exektion till vad du för närvarande behöver.

MapReduce delar en liknande princip, där du kan inkludera en beräknad "poäng" i en del av den primära nyckeln som sänds ut som det ledande elementet. MapReduce sorterar naturligt all input som sänds ut av denna nyckel som en optimering för matning till en reduceringsfunktion. Du kan dock inte ytterligare sortera eller "begränsa" ett sådant resultat.

Dessa är i allmänhet dina alternativ att titta på och avgöra vilket som passar ditt fall bäst.




  1. Loopback:nära filter på objekts underfält

  2. mongodb flera aggregationer i en operation

  3. MongoDB - DBRef

  4. Frågar med joins och filter i Mongoose