Aggregate for non-zero increasing values












1















TL;DR



Is there a mongo array operator that can detect if an array contains at least one entry that's larger than the previous? eg



 [1,1,1,2,2,2] -> true
[1,1,1,0,0,0] -> false




We're using mongo to track network activity, where the relative field packets is the running sum of activity over time. This is best illustrated by example:



[0,0,0,0] -> no packets
[5,5,5,5] -> 5 packets continuous
[0,0,5,5] -> No packets and then a single event of 5
[0,0,5,10] -> two events, each increasing total packets by 5


Our goal is to identify records where there has been activity (ie. the number of packets changes). At first, this seems straightforward using the $addToSet operator and then taking sets where count > 1. EG:



[0,0,0,0] -> [0] -> false
[5,5,5,5] -> [5] -> false
[0,0,5,5] -> [0,5] -> true
[0,0,5,10] -> [0,5,10] -> true


However, we then learned of an additional constraint. When activity goes to 0, that is considered a reset and should not count as activity eg,



[5,5,0,0] -> false (a reset event)
[0,0,5,5] -> true (a network event)
[5,0,5,0] -> true (a reset event followed be a network event followed by a reset - but because there was a network event this is true)


Activity will ALWAYS increase except for when going to zero (ie [5,5,0,0] is possible but [5,5,4,4] is not).



Thus, we need to find out if the data contains a single entry whose value is larger than the prior. Is there a mongo operator that can sweep through an array and return true if any element is larger than its prior?



Thanks










share|improve this question

























  • Just to be clear, what's [5,0,5,0] in your expectation? True or False?

    – Neil Lunn
    Nov 23 '18 at 20:55











  • True - let me update question to reflect

    – Adam Hughes
    Nov 23 '18 at 22:50











  • Oh okay, was a bit worried about that, since that was the only test I was failing. Hate to pick but you just upvoted an answer which actually fails your test cases.

    – Neil Lunn
    Nov 23 '18 at 22:52
















1















TL;DR



Is there a mongo array operator that can detect if an array contains at least one entry that's larger than the previous? eg



 [1,1,1,2,2,2] -> true
[1,1,1,0,0,0] -> false




We're using mongo to track network activity, where the relative field packets is the running sum of activity over time. This is best illustrated by example:



[0,0,0,0] -> no packets
[5,5,5,5] -> 5 packets continuous
[0,0,5,5] -> No packets and then a single event of 5
[0,0,5,10] -> two events, each increasing total packets by 5


Our goal is to identify records where there has been activity (ie. the number of packets changes). At first, this seems straightforward using the $addToSet operator and then taking sets where count > 1. EG:



[0,0,0,0] -> [0] -> false
[5,5,5,5] -> [5] -> false
[0,0,5,5] -> [0,5] -> true
[0,0,5,10] -> [0,5,10] -> true


However, we then learned of an additional constraint. When activity goes to 0, that is considered a reset and should not count as activity eg,



[5,5,0,0] -> false (a reset event)
[0,0,5,5] -> true (a network event)
[5,0,5,0] -> true (a reset event followed be a network event followed by a reset - but because there was a network event this is true)


Activity will ALWAYS increase except for when going to zero (ie [5,5,0,0] is possible but [5,5,4,4] is not).



Thus, we need to find out if the data contains a single entry whose value is larger than the prior. Is there a mongo operator that can sweep through an array and return true if any element is larger than its prior?



Thanks










share|improve this question

























  • Just to be clear, what's [5,0,5,0] in your expectation? True or False?

    – Neil Lunn
    Nov 23 '18 at 20:55











  • True - let me update question to reflect

    – Adam Hughes
    Nov 23 '18 at 22:50











  • Oh okay, was a bit worried about that, since that was the only test I was failing. Hate to pick but you just upvoted an answer which actually fails your test cases.

    – Neil Lunn
    Nov 23 '18 at 22:52














1












1








1








TL;DR



Is there a mongo array operator that can detect if an array contains at least one entry that's larger than the previous? eg



 [1,1,1,2,2,2] -> true
[1,1,1,0,0,0] -> false




We're using mongo to track network activity, where the relative field packets is the running sum of activity over time. This is best illustrated by example:



[0,0,0,0] -> no packets
[5,5,5,5] -> 5 packets continuous
[0,0,5,5] -> No packets and then a single event of 5
[0,0,5,10] -> two events, each increasing total packets by 5


Our goal is to identify records where there has been activity (ie. the number of packets changes). At first, this seems straightforward using the $addToSet operator and then taking sets where count > 1. EG:



[0,0,0,0] -> [0] -> false
[5,5,5,5] -> [5] -> false
[0,0,5,5] -> [0,5] -> true
[0,0,5,10] -> [0,5,10] -> true


However, we then learned of an additional constraint. When activity goes to 0, that is considered a reset and should not count as activity eg,



[5,5,0,0] -> false (a reset event)
[0,0,5,5] -> true (a network event)
[5,0,5,0] -> true (a reset event followed be a network event followed by a reset - but because there was a network event this is true)


Activity will ALWAYS increase except for when going to zero (ie [5,5,0,0] is possible but [5,5,4,4] is not).



Thus, we need to find out if the data contains a single entry whose value is larger than the prior. Is there a mongo operator that can sweep through an array and return true if any element is larger than its prior?



Thanks










share|improve this question
















TL;DR



Is there a mongo array operator that can detect if an array contains at least one entry that's larger than the previous? eg



 [1,1,1,2,2,2] -> true
[1,1,1,0,0,0] -> false




We're using mongo to track network activity, where the relative field packets is the running sum of activity over time. This is best illustrated by example:



[0,0,0,0] -> no packets
[5,5,5,5] -> 5 packets continuous
[0,0,5,5] -> No packets and then a single event of 5
[0,0,5,10] -> two events, each increasing total packets by 5


Our goal is to identify records where there has been activity (ie. the number of packets changes). At first, this seems straightforward using the $addToSet operator and then taking sets where count > 1. EG:



[0,0,0,0] -> [0] -> false
[5,5,5,5] -> [5] -> false
[0,0,5,5] -> [0,5] -> true
[0,0,5,10] -> [0,5,10] -> true


However, we then learned of an additional constraint. When activity goes to 0, that is considered a reset and should not count as activity eg,



[5,5,0,0] -> false (a reset event)
[0,0,5,5] -> true (a network event)
[5,0,5,0] -> true (a reset event followed be a network event followed by a reset - but because there was a network event this is true)


Activity will ALWAYS increase except for when going to zero (ie [5,5,0,0] is possible but [5,5,4,4] is not).



Thus, we need to find out if the data contains a single entry whose value is larger than the prior. Is there a mongo operator that can sweep through an array and return true if any element is larger than its prior?



Thanks







mongodb set






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 23 '18 at 22:51







Adam Hughes

















asked Nov 23 '18 at 20:48









Adam HughesAdam Hughes

4,54612752




4,54612752













  • Just to be clear, what's [5,0,5,0] in your expectation? True or False?

    – Neil Lunn
    Nov 23 '18 at 20:55











  • True - let me update question to reflect

    – Adam Hughes
    Nov 23 '18 at 22:50











  • Oh okay, was a bit worried about that, since that was the only test I was failing. Hate to pick but you just upvoted an answer which actually fails your test cases.

    – Neil Lunn
    Nov 23 '18 at 22:52



















  • Just to be clear, what's [5,0,5,0] in your expectation? True or False?

    – Neil Lunn
    Nov 23 '18 at 20:55











  • True - let me update question to reflect

    – Adam Hughes
    Nov 23 '18 at 22:50











  • Oh okay, was a bit worried about that, since that was the only test I was failing. Hate to pick but you just upvoted an answer which actually fails your test cases.

    – Neil Lunn
    Nov 23 '18 at 22:52

















Just to be clear, what's [5,0,5,0] in your expectation? True or False?

– Neil Lunn
Nov 23 '18 at 20:55





Just to be clear, what's [5,0,5,0] in your expectation? True or False?

– Neil Lunn
Nov 23 '18 at 20:55













True - let me update question to reflect

– Adam Hughes
Nov 23 '18 at 22:50





True - let me update question to reflect

– Adam Hughes
Nov 23 '18 at 22:50













Oh okay, was a bit worried about that, since that was the only test I was failing. Hate to pick but you just upvoted an answer which actually fails your test cases.

– Neil Lunn
Nov 23 '18 at 22:52





Oh okay, was a bit worried about that, since that was the only test I was failing. Hate to pick but you just upvoted an answer which actually fails your test cases.

– Neil Lunn
Nov 23 '18 at 22:52












2 Answers
2






active

oldest

votes


















1














You can take advantage of $reduce operator to scan the array and keep previous value to compare it with current one.



For sample data like:



db.col.save({ data: [1,1,1,2,2,2] })
db.col.save({ data: [1,1,1,0,0,0] })


you can run:



db.col.aggregate([
{
$project: {
result: {
$reduce: {
input: "$data",
initialValue: {
previous: { $arrayElemAt: [ "$data", 0 ] },
decision: false
},
in: {
previous: "$$this",
decision: {
$or: [
"$$value.decision",
{ $gt: [ "$$this", "$$value.previous" ] }
]
}
}
}
}
}
},
{
$project: {
_id: 0,
result: "$result.decision"
}
}
])


outputs:



{ "result" : true }
{ "result" : false }





share|improve this answer


























  • Thanks, let me try this out a bit later and mark as accepted if it works which it seems to nicely

    – Adam Hughes
    Nov 23 '18 at 22:51











  • @AdamHughes sure, you can also test it here: mongoplayground.net/p/7A1qWH1Qcur

    – mickl
    Nov 24 '18 at 7:06



















1














Basically you are traversing with $reduce using current and previous values and comparing



db.collection.aggregate([
{ "$addFields": {
"result": {
"$reduce": {
"input": {
"$range": [ 1, { "$size": "$source_array" } ]
},
"initialValue": false,
"in": {
"$or": [
"$$value",
{ "$gt": [
{ "$arrayElemAt": [ "$source_array", "$$this" ]},
{ "$arrayElemAt": [
"$source_array",
{ "$subtract": [ "$$this", 1 ] }
]}
]}
]
}
}
}
}}
]);


Given data like:



{ "source_array" : [ 0, 0, 0, 0 ], "expect" : false }
{ "source_array" : [ 5, 5, 5, 5 ], "expect" : false }
{ "source_array" : [ 0, 0, 5, 5 ], "expect" : true }
{ "source_array" : [ 5, 5, 0, 0 ], "expect" : false }
{ "source_array" : [ 5, 0, 5, 0 ], "expect" : true }
{ "source_array" : [ 5, 0, 5, 5 ], "expect" : true }
{ "source_array" : [ 5, 5, 4, 4 ], "expect" : false }


Returns:



[
{
"source_array": [
0,
0,
0,
0
],
"expect": false,
"result": false
},
{
"source_array": [
5,
5,
5,
5
],
"expect": false,
"result": false
},
{
"source_array": [
0,
0,
5,
5
],
"expect": true,
"result": true
},
{
"source_array": [
5,
5,
0,
0
],
"expect": false,
"result": false
},
{
"source_array": [
5,
0,
5,
0
],
"expect": true,
"result": true
},
{
"source_array": [
5,
0,
5,
5
],
"expect": true,
"result": true
},
{
"source_array": [
5,
5,
4,
4
],
"expect": false,
"result": false
}
]


All this is done by using $arrayElemAt with the index values from the array. Using $range to generate the indexes from 1..length and comparing n with n-1 for current and previous respectively.



The logic says that no further comparison is needed when a true result is obtained.






share|improve this answer

























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53452790%2faggregate-for-non-zero-increasing-values%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    You can take advantage of $reduce operator to scan the array and keep previous value to compare it with current one.



    For sample data like:



    db.col.save({ data: [1,1,1,2,2,2] })
    db.col.save({ data: [1,1,1,0,0,0] })


    you can run:



    db.col.aggregate([
    {
    $project: {
    result: {
    $reduce: {
    input: "$data",
    initialValue: {
    previous: { $arrayElemAt: [ "$data", 0 ] },
    decision: false
    },
    in: {
    previous: "$$this",
    decision: {
    $or: [
    "$$value.decision",
    { $gt: [ "$$this", "$$value.previous" ] }
    ]
    }
    }
    }
    }
    }
    },
    {
    $project: {
    _id: 0,
    result: "$result.decision"
    }
    }
    ])


    outputs:



    { "result" : true }
    { "result" : false }





    share|improve this answer


























    • Thanks, let me try this out a bit later and mark as accepted if it works which it seems to nicely

      – Adam Hughes
      Nov 23 '18 at 22:51











    • @AdamHughes sure, you can also test it here: mongoplayground.net/p/7A1qWH1Qcur

      – mickl
      Nov 24 '18 at 7:06
















    1














    You can take advantage of $reduce operator to scan the array and keep previous value to compare it with current one.



    For sample data like:



    db.col.save({ data: [1,1,1,2,2,2] })
    db.col.save({ data: [1,1,1,0,0,0] })


    you can run:



    db.col.aggregate([
    {
    $project: {
    result: {
    $reduce: {
    input: "$data",
    initialValue: {
    previous: { $arrayElemAt: [ "$data", 0 ] },
    decision: false
    },
    in: {
    previous: "$$this",
    decision: {
    $or: [
    "$$value.decision",
    { $gt: [ "$$this", "$$value.previous" ] }
    ]
    }
    }
    }
    }
    }
    },
    {
    $project: {
    _id: 0,
    result: "$result.decision"
    }
    }
    ])


    outputs:



    { "result" : true }
    { "result" : false }





    share|improve this answer


























    • Thanks, let me try this out a bit later and mark as accepted if it works which it seems to nicely

      – Adam Hughes
      Nov 23 '18 at 22:51











    • @AdamHughes sure, you can also test it here: mongoplayground.net/p/7A1qWH1Qcur

      – mickl
      Nov 24 '18 at 7:06














    1












    1








    1







    You can take advantage of $reduce operator to scan the array and keep previous value to compare it with current one.



    For sample data like:



    db.col.save({ data: [1,1,1,2,2,2] })
    db.col.save({ data: [1,1,1,0,0,0] })


    you can run:



    db.col.aggregate([
    {
    $project: {
    result: {
    $reduce: {
    input: "$data",
    initialValue: {
    previous: { $arrayElemAt: [ "$data", 0 ] },
    decision: false
    },
    in: {
    previous: "$$this",
    decision: {
    $or: [
    "$$value.decision",
    { $gt: [ "$$this", "$$value.previous" ] }
    ]
    }
    }
    }
    }
    }
    },
    {
    $project: {
    _id: 0,
    result: "$result.decision"
    }
    }
    ])


    outputs:



    { "result" : true }
    { "result" : false }





    share|improve this answer















    You can take advantage of $reduce operator to scan the array and keep previous value to compare it with current one.



    For sample data like:



    db.col.save({ data: [1,1,1,2,2,2] })
    db.col.save({ data: [1,1,1,0,0,0] })


    you can run:



    db.col.aggregate([
    {
    $project: {
    result: {
    $reduce: {
    input: "$data",
    initialValue: {
    previous: { $arrayElemAt: [ "$data", 0 ] },
    decision: false
    },
    in: {
    previous: "$$this",
    decision: {
    $or: [
    "$$value.decision",
    { $gt: [ "$$this", "$$value.previous" ] }
    ]
    }
    }
    }
    }
    }
    },
    {
    $project: {
    _id: 0,
    result: "$result.decision"
    }
    }
    ])


    outputs:



    { "result" : true }
    { "result" : false }






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 24 '18 at 6:29

























    answered Nov 23 '18 at 21:00









    micklmickl

    12.4k51536




    12.4k51536













    • Thanks, let me try this out a bit later and mark as accepted if it works which it seems to nicely

      – Adam Hughes
      Nov 23 '18 at 22:51











    • @AdamHughes sure, you can also test it here: mongoplayground.net/p/7A1qWH1Qcur

      – mickl
      Nov 24 '18 at 7:06



















    • Thanks, let me try this out a bit later and mark as accepted if it works which it seems to nicely

      – Adam Hughes
      Nov 23 '18 at 22:51











    • @AdamHughes sure, you can also test it here: mongoplayground.net/p/7A1qWH1Qcur

      – mickl
      Nov 24 '18 at 7:06

















    Thanks, let me try this out a bit later and mark as accepted if it works which it seems to nicely

    – Adam Hughes
    Nov 23 '18 at 22:51





    Thanks, let me try this out a bit later and mark as accepted if it works which it seems to nicely

    – Adam Hughes
    Nov 23 '18 at 22:51













    @AdamHughes sure, you can also test it here: mongoplayground.net/p/7A1qWH1Qcur

    – mickl
    Nov 24 '18 at 7:06





    @AdamHughes sure, you can also test it here: mongoplayground.net/p/7A1qWH1Qcur

    – mickl
    Nov 24 '18 at 7:06













    1














    Basically you are traversing with $reduce using current and previous values and comparing



    db.collection.aggregate([
    { "$addFields": {
    "result": {
    "$reduce": {
    "input": {
    "$range": [ 1, { "$size": "$source_array" } ]
    },
    "initialValue": false,
    "in": {
    "$or": [
    "$$value",
    { "$gt": [
    { "$arrayElemAt": [ "$source_array", "$$this" ]},
    { "$arrayElemAt": [
    "$source_array",
    { "$subtract": [ "$$this", 1 ] }
    ]}
    ]}
    ]
    }
    }
    }
    }}
    ]);


    Given data like:



    { "source_array" : [ 0, 0, 0, 0 ], "expect" : false }
    { "source_array" : [ 5, 5, 5, 5 ], "expect" : false }
    { "source_array" : [ 0, 0, 5, 5 ], "expect" : true }
    { "source_array" : [ 5, 5, 0, 0 ], "expect" : false }
    { "source_array" : [ 5, 0, 5, 0 ], "expect" : true }
    { "source_array" : [ 5, 0, 5, 5 ], "expect" : true }
    { "source_array" : [ 5, 5, 4, 4 ], "expect" : false }


    Returns:



    [
    {
    "source_array": [
    0,
    0,
    0,
    0
    ],
    "expect": false,
    "result": false
    },
    {
    "source_array": [
    5,
    5,
    5,
    5
    ],
    "expect": false,
    "result": false
    },
    {
    "source_array": [
    0,
    0,
    5,
    5
    ],
    "expect": true,
    "result": true
    },
    {
    "source_array": [
    5,
    5,
    0,
    0
    ],
    "expect": false,
    "result": false
    },
    {
    "source_array": [
    5,
    0,
    5,
    0
    ],
    "expect": true,
    "result": true
    },
    {
    "source_array": [
    5,
    0,
    5,
    5
    ],
    "expect": true,
    "result": true
    },
    {
    "source_array": [
    5,
    5,
    4,
    4
    ],
    "expect": false,
    "result": false
    }
    ]


    All this is done by using $arrayElemAt with the index values from the array. Using $range to generate the indexes from 1..length and comparing n with n-1 for current and previous respectively.



    The logic says that no further comparison is needed when a true result is obtained.






    share|improve this answer






























      1














      Basically you are traversing with $reduce using current and previous values and comparing



      db.collection.aggregate([
      { "$addFields": {
      "result": {
      "$reduce": {
      "input": {
      "$range": [ 1, { "$size": "$source_array" } ]
      },
      "initialValue": false,
      "in": {
      "$or": [
      "$$value",
      { "$gt": [
      { "$arrayElemAt": [ "$source_array", "$$this" ]},
      { "$arrayElemAt": [
      "$source_array",
      { "$subtract": [ "$$this", 1 ] }
      ]}
      ]}
      ]
      }
      }
      }
      }}
      ]);


      Given data like:



      { "source_array" : [ 0, 0, 0, 0 ], "expect" : false }
      { "source_array" : [ 5, 5, 5, 5 ], "expect" : false }
      { "source_array" : [ 0, 0, 5, 5 ], "expect" : true }
      { "source_array" : [ 5, 5, 0, 0 ], "expect" : false }
      { "source_array" : [ 5, 0, 5, 0 ], "expect" : true }
      { "source_array" : [ 5, 0, 5, 5 ], "expect" : true }
      { "source_array" : [ 5, 5, 4, 4 ], "expect" : false }


      Returns:



      [
      {
      "source_array": [
      0,
      0,
      0,
      0
      ],
      "expect": false,
      "result": false
      },
      {
      "source_array": [
      5,
      5,
      5,
      5
      ],
      "expect": false,
      "result": false
      },
      {
      "source_array": [
      0,
      0,
      5,
      5
      ],
      "expect": true,
      "result": true
      },
      {
      "source_array": [
      5,
      5,
      0,
      0
      ],
      "expect": false,
      "result": false
      },
      {
      "source_array": [
      5,
      0,
      5,
      0
      ],
      "expect": true,
      "result": true
      },
      {
      "source_array": [
      5,
      0,
      5,
      5
      ],
      "expect": true,
      "result": true
      },
      {
      "source_array": [
      5,
      5,
      4,
      4
      ],
      "expect": false,
      "result": false
      }
      ]


      All this is done by using $arrayElemAt with the index values from the array. Using $range to generate the indexes from 1..length and comparing n with n-1 for current and previous respectively.



      The logic says that no further comparison is needed when a true result is obtained.






      share|improve this answer




























        1












        1








        1







        Basically you are traversing with $reduce using current and previous values and comparing



        db.collection.aggregate([
        { "$addFields": {
        "result": {
        "$reduce": {
        "input": {
        "$range": [ 1, { "$size": "$source_array" } ]
        },
        "initialValue": false,
        "in": {
        "$or": [
        "$$value",
        { "$gt": [
        { "$arrayElemAt": [ "$source_array", "$$this" ]},
        { "$arrayElemAt": [
        "$source_array",
        { "$subtract": [ "$$this", 1 ] }
        ]}
        ]}
        ]
        }
        }
        }
        }}
        ]);


        Given data like:



        { "source_array" : [ 0, 0, 0, 0 ], "expect" : false }
        { "source_array" : [ 5, 5, 5, 5 ], "expect" : false }
        { "source_array" : [ 0, 0, 5, 5 ], "expect" : true }
        { "source_array" : [ 5, 5, 0, 0 ], "expect" : false }
        { "source_array" : [ 5, 0, 5, 0 ], "expect" : true }
        { "source_array" : [ 5, 0, 5, 5 ], "expect" : true }
        { "source_array" : [ 5, 5, 4, 4 ], "expect" : false }


        Returns:



        [
        {
        "source_array": [
        0,
        0,
        0,
        0
        ],
        "expect": false,
        "result": false
        },
        {
        "source_array": [
        5,
        5,
        5,
        5
        ],
        "expect": false,
        "result": false
        },
        {
        "source_array": [
        0,
        0,
        5,
        5
        ],
        "expect": true,
        "result": true
        },
        {
        "source_array": [
        5,
        5,
        0,
        0
        ],
        "expect": false,
        "result": false
        },
        {
        "source_array": [
        5,
        0,
        5,
        0
        ],
        "expect": true,
        "result": true
        },
        {
        "source_array": [
        5,
        0,
        5,
        5
        ],
        "expect": true,
        "result": true
        },
        {
        "source_array": [
        5,
        5,
        4,
        4
        ],
        "expect": false,
        "result": false
        }
        ]


        All this is done by using $arrayElemAt with the index values from the array. Using $range to generate the indexes from 1..length and comparing n with n-1 for current and previous respectively.



        The logic says that no further comparison is needed when a true result is obtained.






        share|improve this answer















        Basically you are traversing with $reduce using current and previous values and comparing



        db.collection.aggregate([
        { "$addFields": {
        "result": {
        "$reduce": {
        "input": {
        "$range": [ 1, { "$size": "$source_array" } ]
        },
        "initialValue": false,
        "in": {
        "$or": [
        "$$value",
        { "$gt": [
        { "$arrayElemAt": [ "$source_array", "$$this" ]},
        { "$arrayElemAt": [
        "$source_array",
        { "$subtract": [ "$$this", 1 ] }
        ]}
        ]}
        ]
        }
        }
        }
        }}
        ]);


        Given data like:



        { "source_array" : [ 0, 0, 0, 0 ], "expect" : false }
        { "source_array" : [ 5, 5, 5, 5 ], "expect" : false }
        { "source_array" : [ 0, 0, 5, 5 ], "expect" : true }
        { "source_array" : [ 5, 5, 0, 0 ], "expect" : false }
        { "source_array" : [ 5, 0, 5, 0 ], "expect" : true }
        { "source_array" : [ 5, 0, 5, 5 ], "expect" : true }
        { "source_array" : [ 5, 5, 4, 4 ], "expect" : false }


        Returns:



        [
        {
        "source_array": [
        0,
        0,
        0,
        0
        ],
        "expect": false,
        "result": false
        },
        {
        "source_array": [
        5,
        5,
        5,
        5
        ],
        "expect": false,
        "result": false
        },
        {
        "source_array": [
        0,
        0,
        5,
        5
        ],
        "expect": true,
        "result": true
        },
        {
        "source_array": [
        5,
        5,
        0,
        0
        ],
        "expect": false,
        "result": false
        },
        {
        "source_array": [
        5,
        0,
        5,
        0
        ],
        "expect": true,
        "result": true
        },
        {
        "source_array": [
        5,
        0,
        5,
        5
        ],
        "expect": true,
        "result": true
        },
        {
        "source_array": [
        5,
        5,
        4,
        4
        ],
        "expect": false,
        "result": false
        }
        ]


        All this is done by using $arrayElemAt with the index values from the array. Using $range to generate the indexes from 1..length and comparing n with n-1 for current and previous respectively.



        The logic says that no further comparison is needed when a true result is obtained.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 23 '18 at 23:02

























        answered Nov 23 '18 at 21:01









        Neil LunnNeil Lunn

        97.5k23174184




        97.5k23174184






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53452790%2faggregate-for-non-zero-increasing-values%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Berounka

            Sphinx de Gizeh

            Different font size/position of beamer's navigation symbols template's content depending on regular/plain...