MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Mongoose - Procure texto em três campos com base na pontuação ou peso


Um "índice de texto" e pesquisar é provavelmente a melhor opção aqui, desde que você esteja procurando por palavras inteiras.

Adicionar um índice de texto à sua definição de esquema é bastante simples:
BookSchema.index(
    {
         "name": "text",
         "description": "text",
         "body": "text"
    },
    {
        "weights": {
            "name": 5,
            "description": 2
        }
    }
)

Isso permite realizar pesquisas simples com ponderação "definida" para os campos:
Book.find({ "$text": { "$search": "Holiday School Year" } })
    .select({ "score": { "$meta": "textScore" } })
    .sort({ "score": { "$meta": "textScore" } })
    .exec(function(err,result) {

    }
);

Onde cada termo correspondido será considerado em relação ao campo em que foi encontrado o que dá mais peso e o número de ocorrências.

A atribuição dos pesos é anexada ao "índice", portanto, a definição é feita uma vez e não pode ser alterada. Outra limitação é que na "pesquisa de texto" não olha palavras "parciais". Por exemplo, "ci" não corresponde a "Cidade" ou "Cidadão" e, para isso, você precisaria de uma expressão regular.

Se você precisava de mais flexibilidade do que isso ou geralmente deve ser capaz de alterar dinamicamente a ponderação dos resultados, então você precisa de algo como a estrutura de agregação ou mapReduce.

No entanto, a estrutura de agregação não pode executar uma correspondência "logical" operação (pode filtrar através do $match operador, mas não uma correspondência "lógica" ) de uma "expressão regular" para seus termos. Você pode trabalhar com palavras únicas e correspondências "exatas", se isso for adequado.
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 um pipeline de agregação usa uma estrutura de dados para consultar onde você pode alterar os parâmetros de peso em cada execução para o que você precisa no momento.

O MapReduce compartilha um princípio semelhante, onde você pode incluir uma "pontuação" calculada em parte da chave primária emitida como elemento principal. O MapReduce classifica naturalmente todas as entradas emitidas por essa chave como uma otimização para alimentar uma função de redução. No entanto, você não pode classificar ou "limitar" esse resultado.

Essas são geralmente suas opções para analisar e decidir qual melhor se adequa ao seu caso.