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

Mongodb distinto em um campo de matriz com consulta regex?


A estrutura de agregação e não o .distinct() comando:
db.event.aggregate([
    // De-normalize the array content to separate documents
    { "$unwind": "$tags" },

    // Filter the de-normalized content to remove non-matches
    { "$match": { "tags": /foo/ } },

    // Group the "like" terms as the "key"
    { "$group": {
        "_id": "$tags"
    }}
])

Você provavelmente é melhor usar uma "âncora" no início da regex, quer dizer, no "início" da string. E também fazendo isso $match antes de processar $unwind também:
db.event.aggregate([
    // Match the possible documents. Always the best approach
    { "$match": { "tags": /^foo/ } },

    // De-normalize the array content to separate documents
    { "$unwind": "$tags" },

    // Now "filter" the content to actual matches
    { "$match": { "tags": /^foo/ } },

    // Group the "like" terms as the "key"
    { "$group": {
        "_id": "$tags"
    }}
])

Isso garante que você não esteja processando $unwind em todos os documentos da coleção e apenas naqueles que possivelmente contêm seu valor de "tags correspondentes" antes de "filtrar" para ter certeza.

A maneira realmente "complexa" de mitigar um pouco grandes arrays com possíveis correspondências dá um pouco mais de trabalho, e o MongoDB 2.6 ou superior:
db.event.aggregate([
    { "$match": { "tags": /^foo/ } },
    { "$project": {
        "tags": { "$setDifference": [
            { "$map": {
                "input": "$tags",
                "as": "el",
                "in": { "$cond": [
                    { "$eq": [ 
                        { "$substr": [ "$$el", 0, 3 ] },
                        "foo"
                    ]},
                    "$$el",
                    false
                ]}
            }},
            [false]
        ]}
    }},
    { "$unwind": "$tags" },
    { "$group": { "_id": "$tags" }}
])

Então $map é um bom processador "in-line" de matrizes, mas só pode ir tão longe. O $setDifference operador nega o false correspondências, mas no final das contas você ainda precisa processar $unwind para fazer o $group restante palco para valores distintos em geral.

A vantagem aqui é que os arrays agora são "reduzidos" apenas ao elemento "tags" que corresponde. Só não use isso quando quiser uma "contagem" das ocorrências quando houver "vários valores distintos" no mesmo documento. Mas, novamente, existem outras maneiras de lidar com isso.