我想根据同一文档中可用的 slicingIndex 键对文档中的数组进行切片并推入数组中。
[
{
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 }
]
}
]
输出(预期):
{
"array": [
[
{ "name": 1 },
{ "name": 2 },
{ "name": 3 },
{ "name": 4 }
],
[
{ "name": 5 },
{ "name": 6 },
{ "name": 7 }
],
[
{ "name": 8 },
{ "name": 9 },
{ "name": 10 }
]
]
}
这是我在下面尝试的聚合,但没有按预期工作:
db.collection.aggregate([
{
"$project": {
slicingIndex: 1,
array: {
"$map": {
"input": "$slicingIndex",
"as": "num",
"in": {
"$slice": [
"$array",
"$$num",
{
"$subtract": [
{
"$arrayElemAt": ["$slicingIndex", { "$indexOfArray": ["$slicingIndex", "$$num"] }]
},
"$$num"
]
}
]
}
}
}
}
}
])
MongoDb Playground 链接:https://mongoplayground.net/p/oNzBVLRfIU0
$add
& $indexOfArray
用于从数组中的当前指针获取向前一步元素,如 (n+1)。 $let
:我已将其用作可选,以便在需要时使变量可重用。$map
:遍历数组元素。 $arrayElemAt
:从数组中获取元素。$subtract
:执行类似 [ (n+1) - n ] 的操作,其中 n 是数组中的索引。$filter
:过滤掉元素(在我们的例子中:null)。
db.collection.aggregate([
{
"$project": {
array: {
"$map": {
"input": "$slicingIndex",
"as": "elem",
"in": {
"$let": {
"vars": {
//create variable that holds element one index+1 to the current index
"elemOneStepHeadToElem": {
"$arrayElemAt": [
"$slicingIndex",
{
$add: [
1,
{
"$indexOfArray": [
"$slicingIndex",
"$$elem"
]
}
]
}
]
}
},
"in": {
"$slice": [
"$array",
"$$elem",
{
"$subtract": [
"$$elemOneStepHeadToElem",
"$$elem"
]
}
]
}
}
}
}
}
}
}//remove null from array from last index
,
{
"$project": {
array: {
"$filter": {
"input": "$array",
"cond": {
$ne: [
"$$this",
null
]
}
}
}
}
}
])
棘手的问题!
您应该从
slicingIndex
的第二个元素开始迭代。要对 array
进行切片,您需要使用当前迭代元素的前一个元素的值(当前索引 - 1)获取 ($slice
) 起始索引,并且 n
应该是当前元素 - 前一个元素。
db.collection.aggregate([
{
"$project": {
slicingIndex: 1,
array: {
"$map": {
"input": {
$slice: [
"$slicingIndex",
1,
{
$size: "$slicingIndex"
}
]
},
"as": "num",
"in": {
"$slice": [
"$array",
{
"$arrayElemAt": [
"$slicingIndex",
{
$subtract: [
{
"$indexOfArray": [
"$slicingIndex",
"$$num"
]
},
1
]
}
]
},
{
$subtract: [
"$$num",
{
"$arrayElemAt": [
"$slicingIndex",
{
$subtract: [
{
"$indexOfArray": [
"$slicingIndex",
"$$num"
]
},
1
]
}
]
}
]
}
]
}
}
}
}
}
])
通过将
slicingIndex
与自身进行压缩,为切片的索引对创建两个数组。又名“zip with next”。n
元素,其中 n = 大小减 1。对于结束索引,使用 minus n
表示 slice
从末尾开始。
startIndexes: [0, 4, 7]
和 endIndexes: [4, 7, 10]
multiply { subtract size 1 }, -1
起将
subtract 1 size
更改为
(n - 1) * -1 == 1 - n
然后将这两个压缩在一起以获得开始和结束索引对。
sliceIdxPairs
是 [[0, 4], [4, 7], [7, 10]]
$slice
聚合的参数是position
(起始索引)和n
(元素数量),我们需要的是从每个中的endIndex
中减去startIndex
成对。
sliceParams
是 [[0, 4], [4, 3], [7, 3]]
最后,
$map
sliceParams
中的数字对,并将它们与 $slice
字段上的 array
一起使用。
db.collection.aggregate([
{
$project: {
array: 1,
startIndexes: {
$slice: [
"$slicingIndex",
{ $subtract: [{ $size: "$slicingIndex" }, 1] }
]
},
endIndexes: {
$slice: [
"$slicingIndex",
{ $subtract: [1, { $size: "$slicingIndex" }] }
]
}
}
},
{
$project: {
array: 1,
sliceIdxPairs: {
$zip: { inputs: ["$startIndexes", "$endIndexes"] }
}
}
},
{
$project: {
array: 1,
sliceParams: {
$map: {
input: "$sliceIdxPairs",
as: "ip",
in: [
{ $first: "$$ip" },
{ $subtract: [{ $last: "$$ip" }, { $first: "$$ip" }] }
]
}
}
}
},
{
$project: {
array: {
$map: {
input: "$sliceParams",
as: "pair",
in: {
$slice: [
"$array",
{ $first: "$$pair" },
{ $last: "$$pair" }
]
}
}
}
}
}
])