【问题标题】:remove 0 values if 0 is followed by >=1 from arrays in MongoDB如果 0 后跟 >=1,则从 MongoDB 中的数组中删除 0 值
【发布时间】:2021-11-06 18:16:44
【问题描述】:

data_start 中,如果数组中 0 后跟 >=1,则从 data_start 中删除 0,同时从 time_start 数组中相应删除元素。


{
  "data_start": [
    1,
    1,
    0,
    0,
    1,
    1,
    0
  ],
  "time_start": [
    "2021-09-04T12:18:42Z",
    "2021-09-04T14:59:50Z",
    "2021-09-04T14:59:59Z",
    "2021-09-04T15:00:00Z",
    "2021-09-04T15:00:01Z",
    "2021-09-04T15:05:00Z",
    "2021-09-04T15:05:01Z"
  ]
}

输出文档将是:

{
"data_start": [
    1,
    1,
    0,
    1,
    1,
    0
  ],
  "time_start": [
    "2021-09-04T12:18:42Z",
    "2021-09-04T14:59:50Z",
    "2021-09-04T14:59:59Z",
    "2021-09-04T15:00:01Z",
    "2021-09-04T15:05:00Z",
    "2021-09-04T15:05:01Z"
  ]
}

【问题讨论】:

    标签: arrays mongodb mongoose mongodb-query aggregation-framework


    【解决方案1】:

    这在 Mongo 中有点难看,但有可能,我们的策略是首先遍历数组并计算我们需要删除的项目的索引,一旦我们有了这些,我们将再次遍历这两个数组并更新它们,最后我们删除临时计算值,如下所示:

    请注意,要纯粹在 Mongo 中执行此操作,您需要使用 v4.2+,因为如果您使用的是较低版本,我们需要使用 pipelined updates,那么您将在代码中执行此逻辑。

    db.collection.updateOne(
    {},
    [
      {
        $set: {
          tmpField: {
            $reduce: {
              input: {
                $zip: {
                  "inputs": [
                    {
                      $reverseArray: "$data_start"
                    },
                    {
                      $range: [
                        {
                          $subtract: [
                            {
                              $size: "$data_start"
                            },
                            1
                          ]
                        },
                        0,
                        -1
                      ]
                    }
                  ]
                }
              },
              initialValue: {
                prev: null,
                indexesToRemove: []
              },
              in: {
                prev: {
                  $arrayElemAt: [
                    "$$this",
                    0
                  ]
                },
                indexesToRemove: {
                  $concatArrays: [
                    "$$value.indexesToRemove",
                    {
                      $cond: [
                        {
                          $and: [
                            {
                              $eq: [
                                "$$value.prev",
                                1
                              ]
                            },
                            {
                              $eq: [
                                {
                                  $arrayElemAt: [
                                    "$$this",
                                    0
                                  ]
                                },
                                0
                              ]
                            }
                          ]
                        },
                        [
                          {
                            $arrayElemAt: [
                              "$$this",
                              1
                            ]
                          }
                        ],
                        []
                      ]
                    }
                  ]
                }
              }
            }
          }
        }
      },
      {
        $addFields: {
          data_start: {
            $reduce: {
              input: {
                $zip: {
                  "inputs": [
                    "$data_start",
                    {
                      $range: [
                        0,
                        {
                          $size: "$data_start"
                        }
                      ]
                    }
                  ]
                }
              },
              initialValue: [],
              in: {
                $cond: [
                  {
                    $in: [
                      {
                        $arrayElemAt: [
                          "$$this",
                          1
                        ]
                      },
                      "$tmpField.indexesToRemove"
                    ]
                  },
                  "$$value",
                  {
                    $concatArrays: [
                      "$$value",
                      [
                        {
                          $arrayElemAt: [
                            "$$this",
                            0
                          ]
                        }
                      ]
                    ]
                  }
                ]
              }
            }
          },
          time_start: {
            $reduce: {
              input: {
                $zip: {
                  "inputs": [
                    "$time_start",
                    {
                      $range: [
                        0,
                        {
                          $size: "$time_start"
                        }
                      ]
                    }
                  ]
                }
              },
              initialValue: [],
              in: {
                $cond: [
                  {
                    $in: [
                      {
                        $arrayElemAt: [
                          "$$this",
                          1
                        ]
                      },
                      "$tmpField.indexesToRemove"
                    ]
                  },
                  "$$value",
                  {
                    $concatArrays: [
                      "$$value",
                      [
                        {
                          $arrayElemAt: [
                            "$$this",
                            0
                          ]
                        }
                      ]
                    ]
                  }
                ]
              }
            }
          }
        }
      },
      {
        $unset: "tmpField"
      }
    ])
    

    Mongo Playground

    【讨论】:

    • 使用3次$reduce + $concatArrays,如果你有更大的数据可能会导致性能问题,请参阅Performance issue for $reduce vs. $map
    • 有趣...绝对值得大规模考虑。
    • 不知道,我只通过$concatArrays获得了这种体验
    【解决方案2】:

    一种方法是这样的:

    db.collection.aggregate([
       {
          $set: {
             data: {
                $let: {
                   vars: {
                      val: "$data_start",
                      prev: { $concatArrays: [[null], "$data_start"] } // shift values by one element 
                   },
                   in: {
                      $map: {
                         input: { $range: [0, { $size: "$$val" }] },
                         as: "idx",
                         in: {
                            $cond: {
                               if: {
                                  $and: [
                                     { $eq: [{ $arrayElemAt: ["$$val", "$$idx"] }, 0] }, // is 0
                                     { $eq: [{ $arrayElemAt: ["$$val", "$$idx"] }, { $arrayElemAt: ["$$prev", "$$idx"] }] } // is equal to previous
                                  ]
                               },
                               then: null,
                               else: {
                                  data_start: { $arrayElemAt: ["$$val", "$$idx"] },
                                  time_start: { $arrayElemAt: ["$time_start", "$$idx"] }
                               }
                            }
                         }
                      }
                   }
                }
             }
          }
       },
       {
          $set: {
             data: {
                $filter: {
                   input: "$data",
                   cond: "$$this"// -> removes null's from array
                }
             }
          }
       }
    ])
    

    也许您必须微调条件和/或反转循环,即input: { $range: [{ $size: "$$val" }, 0, -1] }

    Mongo playground

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-30
      • 2020-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多