sql >> Database >  >> NoSQL >> MongoDB

Mongoose - Zoek naar tekst in drie velden op basis van score of gewicht

Een "text index" en zoeken is inderdaad waarschijnlijk de beste optie hier zolang je zoekt naar hele woorden.

Het toevoegen van een tekstindex aan uw schemadefinitie is vrij eenvoudig:

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

Dit stelt u in staat om eenvoudige zoekopdrachten uit te voeren met "set" weging naar de velden:

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

    }
);

Waar elke overeenkomende term wordt vergeleken met het veld waarin deze is gevonden, geeft het meeste gewicht en het aantal keren dat het voorkomt.

Het toekennen van de gewichten is gekoppeld aan de "index", dus de definitie gebeurt eenmalig en kan niet worden gewijzigd. Een andere beperking is dat bij "tekst zoeken" niet wordt gekeken naar "gedeeltelijke" woorden. "ci" komt bijvoorbeeld niet overeen met "Stad" of "Burger", en daarvoor zou je in plaats daarvan een reguliere expressie nodig hebben.

Als u meer flexibiliteit nodig had of in het algemeen de weging van resultaten dynamisch moet kunnen wijzigen, dan heeft u iets nodig als het aggregatieraamwerk of mapReduce.

Het aggregatieraamwerk kan echter geen "logische" overeenkomst bewerking (het kan filteren door de $match operator, maar geen "logische" match ) van een "reguliere expressie" met uw termen. Je kunt echter werken met losse woorden en "exacte" overeenkomsten als dit je uitkomt.

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) {

    }
)

Omdat een aggregatiepijplijn een gegevensstructuur gebruikt om te zoeken waar u de parameters voor het gewicht op elke uitvoer kunt wijzigen in wat u op dat moment nodig heeft.

MapReduce deelt een soortgelijk principe, waarbij u een berekende "score" kunt opnemen in een deel van de primaire sleutel die wordt uitgezonden als het leidende element. MapReduce sorteert natuurlijk alle invoer die door deze toets wordt uitgezonden als een optimalisatie voor het voeden naar een reduceerfunctie. U kunt een dergelijk resultaat echter niet verder sorteren of "beperken".

Dat zijn over het algemeen uw opties om naar te kijken en te beslissen welke het beste bij uw geval past.




  1. Redis gebruiken voor wachtrijen voor meerdere Laravel-applicaties op een enkele server

  2. Filter de subarray van een array op enkele criteria

  3. hoe op te lossen:'MongoError:authenticatie mislukt' @MongoDB Atlas

  4. MongoDB - Aggregatieraamwerk (totaal aantal)