Изглежда, че вашият въпрос ясно задава "вземи всеки n-ти екземпляр", което наистина изглежда като доста ясен въпрос.
Операции за заявки като .find()
наистина може да върне документа само „какъвто е“ с изключение на общото поле „избор“ в проекцията и оператори като позиционен $
оператор за съответствие или $elemMatch
които позволяват единичен съответстващ елемент на масив.
Разбира се, има $slice
, но това просто позволява „избор на диапазон“ в масива, така че отново не се прилага.
„Единствените“ неща, които могат да променят резултат на сървъра, са .aggregate()
и .mapReduce()
. Първият не "играе много добре" с "нарязване" на масиви по никакъв начин, поне не с "n" елемента. Въпреки това, тъй като аргументите "function()" на mapReduce са базирана на JavaScript логика, тогава имате малко повече място за игра.
За аналитични процеси и „само“ за аналитични цели просто филтрирайте съдържанието на масива чрез mapReduce, като използвате .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
)
На този етап това наистина е просто "изпълняващ JavaScript", но ако това е само за анализ/тестване, тогава няма нищо лошо в концепцията. Разбира се, резултатът не е "точно" как е структуриран вашият документ, но е толкова близо до факсимиле, колкото mapReduce може да получи.
Другото предложение, което виждам тук, изисква създаване на нова колекция с всички елементи „денормализирани“ и вмъкване на „индекс“ от масива като част от unqique _id
ключ. Това може да произведе нещо, което можете да заявите директно, но за „всеки n-ти елемент“ пак ще трябва да направите:
db.resultCollection.find({
"_id.index": { "$in": [2,5,8,11,14] } // and so on ....
})
Така че разработете и осигурете стойността на индекса на „всеки n-ти елемент“, за да получите „всеки n-ти елемент“. Така че това наистина не изглежда да реши проблема, който беше зададен.
Ако изходната форма изглеждаше по-желана за вашите "тестващи" цели, тогава по-добра последваща заявка за тези резултати би била използването на тръбопровода за агрегиране с $redact
db.newCollection([
{ "$redact": {
"$cond": {
"if": {
"$eq": [
{ "$mod": [ { "$add": [ "$_id.index", 1] }, 3 ] },
0 ]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
Това поне използва „логическо условие“ почти същото като това, което беше приложено с .filter()
преди просто да изберете елементите на "n-тия индекс", без да изброявате всички възможни стойности на индекса като аргумент на заявката.