MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Mongoose - Recherche de texte dans trois champs en fonction du score ou de la pondération

Un "index de texte" et recherche est en effet probablement la meilleure option ici tant que vous recherchez des mots entiers.

L'ajout d'un index de texte à votre définition de schéma est assez simple :

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

Cela vous permet d'effectuer des recherches simples avec une pondération "définie" sur les champs :

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

    }
);

Où chaque terme correspondant sera considéré par rapport au champ dans lequel il a été trouvé qui donne le plus de poids et le nombre d'occurrences.

L'attribution des poids est attachée à "l'indice", de sorte que la définition est faite une fois et ne peut pas être modifiée. Une autre limitation est que la "recherche de texte" ne regarde pas les mots "partiels". Par exemple, "ci" ne correspond pas à "City" ou "Citizen", et pour une telle chose, vous auriez besoin d'une expression régulière à la place.

Si vous avez besoin de plus de flexibilité que cela ou si vous devez généralement être en mesure de modifier dynamiquement la pondération des résultats, vous avez besoin de quelque chose comme le cadre d'agrégation ou mapReduce.

Cependant, le cadre d'agrégation ne peut pas effectuer une correspondance "logique" opération (il peut filtrer à travers le $match opérateur, mais pas une correspondance "logique" ) d'une "expression régulière" avec vos termes. Vous pouvez cependant travailler avec des mots simples et des correspondances "exactes" si cela vous convient.

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

    }
)

Comme un pipeline d'agrégation utilise une structure de données pour interroger où vous pouvez modifier les paramètres de pondération de chaque exécution en fonction de vos besoins actuels.

MapReduce partage un principe similaire, où vous pouvez inclure un "score" calculé dans une partie de la clé primaire émise en tant qu'élément principal. MapReduce trie naturellement toutes les entrées émises par cette clé comme une optimisation pour alimenter une fonction de réduction. Cependant, vous ne pouvez pas trier ou "limiter" davantage un tel résultat.

Ce sont généralement vos options à examiner et à décider laquelle convient le mieux à votre cas.