sql >> Database >  >> NoSQL >> MongoDB

MongoDB-lijsten - ontvang elk N-de item

Het lijkt erop dat uw vraag duidelijk is gesteld "krijg elke nde instantie", wat een vrij duidelijke vraag lijkt.

Query-bewerkingen zoals .find() kan het document eigenlijk alleen retourneren "zoals het is" met uitzondering van het algemene veld "selectie" in projectie en operators zoals de positional $ match-operator of $elemMatch die een enkelvoudig overeenkomend array-element toestaan.

Natuurlijk is er $slice , maar dat staat gewoon een "bereikselectie" op de array toe, dus nogmaals niet van toepassing.

De "enige" dingen die een resultaat op de server kunnen wijzigen zijn .aggregate() en .mapReduce() . De eerste speelt op geen enkele manier "erg goed" met het "slicen" van arrays, althans niet door "n" -elementen. Maar aangezien de "function()"-argumenten van mapReduce op JavaScript gebaseerde logica zijn, heb je wat meer ruimte om mee te spelen.

Voor analytische processen, en voor analytische doeleinden "alleen" filter dan gewoon de array-inhoud via mapReduce met behulp van .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
)

Het is op dit moment eigenlijk gewoon een "JavaScript-runner", maar als dit alleen voor analyse/testen is, is er over het algemeen niets mis met het concept. Natuurlijk is de uitvoer niet "precies" hoe uw document is gestructureerd, maar het is zo dicht bij een facsimile als mapReduce kan krijgen.

De andere suggestie die ik hier zie, vereist het maken van een nieuwe verzameling met alle items "gedenormaliseerd" en het invoegen van de "index" uit de array als onderdeel van de unieke _id sleutel. Dat kan iets opleveren dat je direct kunt opvragen, maar voor het "elke nde item" zou je nog steeds het volgende moeten doen:

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

Dus werk uit en geef de indexwaarde van "elk n-de item" om "elk n-de item" te krijgen. Dus dat lijkt het gevraagde probleem niet echt op te lossen.

Als het uitvoerformulier wenselijker leek voor uw "test" -doeleinden, dan zou een betere daaropvolgende query op die resultaten de aggregatiepijplijn zijn, met $redact

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

Dat gebruikt in ieder geval een "logische voorwaarde" die ongeveer hetzelfde is als wat werd toegepast met .filter() voordat u gewoon de "n-de index"-items selecteert zonder alle mogelijke indexwaarden als een queryargument op te sommen.



  1. Hoe subdocument te wijzigen na het vinden met mangoest

  2. MongoDB en upsert-probleem

  3. Model.find().toArray() beweert geen .toArray()-methode te hebben

  4. How-to:gebruik de Apache HBase REST-interface, deel 3