MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Liste MongoDB:ottieni ogni ennesimo elemento

Sembra che la tua domanda abbia chiesto chiaramente "ottieni ogni ennesima istanza", il che sembra una domanda abbastanza chiara.

Operazioni di query come .find() può davvero restituire solo il documento "così com'è" con l'eccezione del campo generale "selezione" nella proiezione e operatori come posizionale $ operatore di corrispondenza o $elemMatch che consentono un elemento di matrice abbinato singolare.

Naturalmente c'è $slice , ma ciò consente solo una "selezione dell'intervallo" sull'array, quindi ancora una volta non si applica.

Le "solo" cose che possono modificare un risultato sul server sono .aggregate() e .mapReduce() . Il primo non "suona molto bene" con gli array "slicing" in alcun modo, almeno non con "n" elementi. Tuttavia, poiché gli argomenti "function()" di mapReduce sono logici basati su JavaScript, hai un po' più di spazio con cui giocare.

Per i processi analitici e "solo" per scopi analitici, è sufficiente filtrare il contenuto dell'array tramite mapReduce utilizzando .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
)

È davvero solo un "runner JavaScript" a questo punto, ma se questo è solo per analisi/test, in genere non c'è nulla di sbagliato nel concetto. Ovviamente l'output non è "esattamente" come è strutturato il tuo documento, ma è quanto di più simile a un facsimile può ottenere mapReduce.

L'altro suggerimento che vedo qui richiede la creazione di una nuova raccolta con tutti gli elementi "denormalizzati" e l'inserimento dell'"indice" dall'array come parte dell'unqique _id chiave. Ciò potrebbe produrre qualcosa che puoi interrogare direttamente, ma per "ogni ennesima voce" dovresti ancora fare:

db.resultCollection.find({
     "_id.index": { "$in": [2,5,8,11,14] } // and so on ....
})

Quindi calcola e fornisci il valore dell'indice di "ogni ennesima voce" per ottenere "ogni ennesima voce". Quindi non sembra davvero risolvere il problema che è stato chiesto.

Se il modulo di output sembrava più desiderabile per i tuoi scopi di "test", una query successiva migliore su quei risultati sarebbe l'utilizzo della pipeline di aggregazione, con $redact

db.newCollection([
    { "$redact": {
        "$cond": {
            "if": {
                "$eq": [ 
                    { "$mod": [ { "$add": [ "$_id.index", 1] }, 3 ] },
                0 ]
            },
            "then": "$$KEEP",
            "else": "$$PRUNE"
        }
    }}
])

Questo almeno usa una "condizione logica" più o meno la stessa di quella applicata con .filter() prima di selezionare semplicemente gli elementi "nth index" senza elencare tutti i possibili valori di indice come argomento della query.