在 MongoDB 中:从切片索引数组中切片对象数组并通过聚合推入数组

问题描述 投票:0回答:3

我想根据同一文档中可用的 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"
                ]
              }
            ]
          }
        }
      }
    }
  }
])
arrays mongodb aggregation-framework slice
3个回答
2
投票

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
            ]
          }
        }
      }
    }
  }
])

1
投票

棘手的问题!

您应该从

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
                        ]
                      }
                    ]
                  }
                ]
              }
            ]
          }
        }
      }
    }
  }
])

演示@Mongo Playground


1
投票
  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
  2. 然后将这两个压缩在一起以获得开始和结束索引对。

    • sliceIdxPairs
      [[0, 4], [4, 7], [7, 10]]
  3. 但是由于

    $slice
    聚合的参数是
    position
    (起始索引)和
    n
    (元素数量),我们需要的是从每个中的
    endIndex
    中减去
    startIndex
    成对。

    • sliceParams
      [[0, 4], [4, 3], [7, 3]]
  4. 最后,

    $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" }
            ]
          }
        }
      }
    }
  }
])

蒙戈游乐场

© www.soinside.com 2019 - 2024. All rights reserved.