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

Listas do MongoDB - obtenha cada enésimo item


Parece que sua pergunta claramente perguntou "obter cada enésima instância", o que parece uma pergunta bastante clara.

Operações de consulta como .find() só pode retornar o documento "como está" com exceção do campo geral "seleção" na projeção e operadores como o posicional $ operador de correspondência ou $elemMatch que permitem um elemento de matriz com correspondência singular.

Claro que existe $slice , mas isso apenas permite uma "seleção de intervalo" na matriz, então novamente não se aplica.

As "únicas" coisas que podem modificar um resultado no servidor são .aggregate() e .mapReduce() . O primeiro não "joga muito bem" com arrays "slicing" de forma alguma, pelo menos não por "n" elementos. No entanto, como os argumentos "function()" do mapReduce são lógicos baseados em JavaScript, você tem um pouco mais de espaço para brincar.

Para processos analíticos e para fins analíticos "somente", basta filtrar o conteúdo do array via mapReduce usando .filter() :
db.collection.mapReduce(
    function() {
        var id = this._id;
        delete this._id;

        // filter the content of "instances" to every 3rd item only
        this.instances = this.instances.filter(function(el,idx) {
            return ((idx+1) % 3) == 0;
        });
        emit(id,this);
    },
    function() {},
    { "out": { "inline": 1 } } // or output to collection as required
)

É realmente apenas um "corredor JavaScript" neste momento, mas se isso for apenas para análise/teste, não há nada de errado com o conceito. É claro que a saída não é "exatamente" como seu documento está estruturado, mas é o mais próximo de um fac-símile que o mapReduce pode chegar.

A outra sugestão que vejo aqui requer a criação de uma nova coleção com todos os itens "desnormalizados" e a inserção do "índice" do array como parte do exclusivo _id chave. Isso pode produzir algo que você pode consultar diretamente, mas para "todo enésimo item" você ainda teria que fazer:
db.resultCollection.find({
     "_id.index": { "$in": [2,5,8,11,14] } // and so on ....
})

Portanto, calcule e forneça o valor de índice de "todo enésimo item" para obter "todo enésimo item". Então, isso realmente não parece resolver o problema que foi perguntado.

Se o formulário de saída parecer mais desejável para seus propósitos de "teste", uma consulta subsequente melhor nesses resultados seria usar o pipeline de agregação, com $redact
db.newCollection([
    { "$redact": {
        "$cond": {
            "if": {
                "$eq": [ 
                    { "$mod": [ { "$add": [ "$_id.index", 1] }, 3 ] },
                0 ]
            },
            "then": "$$KEEP",
            "else": "$$PRUNE"
        }
    }}
])

Isso pelo menos usa uma "condição lógica" muito parecida com a que foi aplicada com .filter() antes para apenas selecionar os itens do "nº índice" sem listar todos os valores de índice possíveis como um argumento de consulta.