Search code examples
mongodbmongodb-queryaggregation-frameworkaggregate

mongodb aggregation get max number of negative sequence in array


I need to get the max count of negative sequence from array via aggregation , example documents:

  {
  "id": 1,
   x: [ 1,1,-1,-1,1,1,1,-1,-1,-1,-1]
 },
 {
"id": 2,
  x: [ 1,-1,-1,1,1,1,-1 ]
 }

expected result:

 {"id": 1,x:4},
 {"id": 2,x:2}

Please, advice?


Solution

  • You can use $reduce to iterate the array and $cond to apply your logic (consecutive negatives)

    The carrier is in format

         {
            previous: // previous value to compare for continuity 
            acc: // number of consecutive negatives in the current sequence
            max: // length of the longest sequence
          }
    

    $let is to memoise current accumulator to reuse in the max calculation. It's optional yet convenient:

    db.collection.aggregate([
      {
        "$set": {
          "x": {
            "$reduce": {
              "input": "$x",
              "initialValue": {
                previous: 0,
                acc: 0,
                max: 0
              },
              "in": {
                $let: {
                  vars: {
                    result: {
                      "$cond": {
                        "if": {
                          "$and": [
                            {
                              "$lt": [
                                "$$this",
                                0
                              ]
                            },
                            {
                              "$lt": [
                                "$$value.previous",
                                0
                              ]
                            }
                          ]
                        },
                        "then": {
                          "$add": [
                            "$$value.acc",
                            1
                          ]
                        },
                        "else": {
                          "$cond": {
                            "if": {
                              "$lt": [
                                "$$this",
                                0
                              ]
                            },
                            "then": 1,
                            "else": 0
                          }
                        }
                      }
                    }
                  },
                  in: {
                    previous: "$$this",
                    acc: "$$result",
                    max: {
                      "$cond": {
                        "if": {
                          $gt: [
                            "$$value.max",
                            "$$result"
                          ]
                        },
                        "then": "$$value.max",
                        "else": "$$result"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      {
        "$set": {
          x: "$x.max"
        }
      }
    ])
    

    Try it on mongoplayground.net.