I want to slice array in document according to slicingIndex key available in the same document and push into an array.
[
{
slicingIndex: [0, 4, 7, 10],
array: [
{ name: 1 },
{ name: 2 },
{ name: 3 },
{ name: 4 },
{ name: 5 },
{ name: 6 },
{ name: 7 },
{ name: 8 },
{ name: 9 },
{ name: 10 }
]
}
]
Output (expected):
{
"array": [
[
{ "name": 1 },
{ "name": 2 },
{ "name": 3 },
{ "name": 4 }
],
[
{ "name": 5 },
{ "name": 6 },
{ "name": 7 }
],
[
{ "name": 8 },
{ "name": 9 },
{ "name": 10 }
]
]
}
This is what aggregation i tried below but not working as expected:
db.collection.aggregate([
{
"$project": {
slicingIndex: 1,
array: {
"$map": {
"input": "$slicingIndex",
"as": "num",
"in": {
"$slice": [
"$array",
"$$num",
{
"$subtract": [
{
"$arrayElemAt": ["$slicingIndex", { "$indexOfArray": ["$slicingIndex", "$$num"] }]
},
"$$num"
]
}
]
}
}
}
}
}
])
2
Answers
Create two arrays for the pairs of the indexes for the slices, by zipping
slicingIndex
with itself. aka "zip with next".For the start index – take
n
elements where n = size minus 1. And for the end index, start from the end usingminus n
forslice
.startIndexes: [0, 4, 7]
andendIndexes: [4, 7, 10]
multiply { subtract size 1 }, -1
to justsubtract 1 size
since(n - 1) * -1 == 1 - n
Then zip these two together to get Start & End index pairs.
sliceIdxPairs
is[[0, 4], [4, 7], [7, 10]]
But since the params for
$slice
aggregation areposition
(start index) andn
(number of elements), what we need is to subtract theendIndex
from thestartIndex
in each of the pairs.sliceParams
is[[0, 4], [4, 3], [7, 3]]
Finally,
$map
the pairs of numbers in thesliceParams
and use them with$slice
on thearray
field.Mongo Playground
Tricky question!
You should start the iteration from the second element of
slicingIndex
. To slice thearray
, you need to get the ($slice
) start index with the value of the previous element of the current iterated element (current index – 1) and then
should be current element – previous element.Demo @ Mongo Playground