Det lader til, at dit spørgsmål tydeligt stilles "få hver n. forekomst", hvilket virker som et ret klart spørgsmål.
Forespørgselsoperationer som .find()
kan egentlig kun returnere dokumentet "som det er" med undtagelse af det generelle felt "selection" i projektion og operatorer såsom positional $
match operator eller $elemMatch
der tillader et enkelt matchet array-element.
Selvfølgelig er der $slice
, men det tillader bare et "områdevalg" på arrayet, så igen gælder det ikke.
De "kun" ting, der kan ændre et resultat på serveren, er .aggregate()
og .mapReduce()
. Førstnævnte "spiller ikke særlig godt" med at "slice" arrays på nogen måde, i hvert fald ikke efter "n" elementer. Men da "function()"-argumenterne i mapReduce er JavaScript-baseret logik, så har du lidt mere plads at lege med.
Til analytiske processer og "kun" til analytiske formål, så filtrer bare array-indholdet via mapReduce ved hjælp af .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
)
Det er egentlig bare en "JavaScript runner" på dette tidspunkt, men hvis dette kun er til analyse/test, så er der ikke noget generelt galt med konceptet. Selvfølgelig er outputtet ikke "præcis" hvordan dit dokument er struktureret, men det er så tæt på en faksimile som mapReduce kan komme.
Det andet forslag, jeg ser her, kræver oprettelse af en ny samling med alle elementerne "denormaliseret" og indsættelse af "indekset" fra arrayet som en del af det unikke _id
nøgle. Det kan give noget, du kan forespørge direkte på, men for "hver n'te post" skal du stadig gøre:
db.resultCollection.find({
"_id.index": { "$in": [2,5,8,11,14] } // and so on ....
})
Så regn ud og angiv indeksværdien for "hver n. vare" for at få "hver nende vare". Så det ser ikke rigtig ud til at løse det problem, der blev stillet.
Hvis outputformen virkede mere ønskværdig til dine "test"-formål, ville en bedre efterfølgende forespørgsel på disse resultater være at bruge aggregeringspipelinen med $redact
db.newCollection([
{ "$redact": {
"$cond": {
"if": {
"$eq": [
{ "$mod": [ { "$add": [ "$_id.index", 1] }, 3 ] },
0 ]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
Det bruger i det mindste en "logisk betingelse" meget det samme som det, der blev anvendt med .filter()
før blot at vælge de "nte indeks"-elementer uden at angive alle mulige indeksværdier som et forespørgselsargument.