sql >> Base de Datos >  >> NoSQL >> MongoDB

Mongoose:busque texto en tres campos según la puntuación o el peso

Un "índice de texto" y buscar es probablemente la mejor opción aquí, siempre que busque palabras completas.

Agregar un índice de texto a la definición de su esquema es bastante simple:

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

Esto le permite realizar búsquedas simples con ponderación "establecida" en los campos:

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

    }
);

Donde cada término emparejado se considerará contra el campo en el que se encontró que da el mayor peso y el número de ocurrencias.

La asignación de los pesos se adjunta al "índice", por lo que la definición se realiza una vez y no se puede cambiar. Otra limitación es que en la "búsqueda de texto" no se buscan palabras "parciales". Por ejemplo, "ci" no coincide con "Ciudad" o "Ciudadano", y para tal cosa necesitaría una expresión regular en su lugar.

Si necesita más flexibilidad que eso o, en general, debe poder cambiar dinámicamente la ponderación de los resultados, entonces necesita algo como el marco de agregación o mapReduce.

Sin embargo, el marco de agregación no puede realizar una coincidencia "lógica" operación (puede filtrar a través de $match operador, pero no una coincidencia "lógica") de una "expresión regular" con sus términos. Sin embargo, puede trabajar con palabras sueltas y coincidencias "exactas" si le conviene.

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

    }
)

Como canalización de agregación, utiliza una estructura de datos para consultar dónde puede cambiar los parámetros de peso en cada ejecución según lo que necesite actualmente.

MapReduce comparte un principio similar, en el que puede incluir una "puntuación" calculada en parte de la clave principal emitida como elemento principal. MapReduce clasifica de forma natural todas las entradas emitidas por esta tecla como una optimización para alimentar una función de reducción. Sin embargo, no puede ordenar o "limitar" dicho resultado.

Esas son generalmente sus opciones para ver y decidir cuál se adapta mejor a su caso.