R2D2
R2D2

Reputation: 10737

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?

Upvotes: 2

Views: 287

Answers (2)

Alex Blex
Alex Blex

Reputation: 37098

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.

Upvotes: 3

rickhg12hs
rickhg12hs

Reputation: 11942

Here's another way to do it. The general idea is to $reduce the sequence to a string and then $split to make an array filled with strings of each run. Then map the array of strings to an array of string lengths and then take the max.

db.collection.aggregate({
  "$project": {
    "_id": 0,
    "id": 1,
    "x": {
      "$max": {
        "$map": {
          "input": {
            $split: [
              {
                "$reduce": {
                  "input": "$x",
                  "initialValue": "",
                  "in": {
                    $concat: [
                      "$$value",
                      {
                        "$cond": [
                          {
                            "$gt": [
                              "$$this",
                              0
                            ]
                          },
                          "p",
                          "n"
                        ]
                      }
                    ]
                  }
                }
              },
              "p"
            ]
          },
          "in": {
            "$strLenBytes": "$$this"
          }
        }
      }
    }
  }
})

Try it on mongoplayground.net.

Upvotes: 2

Related Questions