Determine the difference between the final value and the second-to-last value within an array

Is there a way to retrieve documents from MongoDB by performing a calculation on two items stored in an array within each document?

Specifically, I am interested in fetching all documents where the last item in an array is lower than the second-to-last item in that same array.

Could someone guide me towards the relevant documentation for achieving this in MongoDB?

Any tips or suggestions would be highly valued. Thank you!

Answer №1

For the most optimal operation in modern MongoDB versions (3.2 and higher), utilizing $redact is recommended as it allows for a "logical filter" based on specified conditions, paired with $arrayElemAt to extract single values from an array.

Consider the following example:

{ "_id": 1, "data": [1,2,3] },
{ "_id": 2, "data": [3,2,1] }

The corresponding query would be:

db.collection.aggregate([
  { "$redact": {
     "$cond": {
       "if": { 
         "$lt": [
           { "$arrayElemAt": [ "$data", -1 ] },
           { "$arrayElemAt": [ "$data", -2 ] }
         ]
       },
       "then": "$$KEEP",
       "else": "$$PRUNE"
     }
  }}
])

In cases where the document includes sub-document properties within the array elements, $map can be applied to extract desired property values for comparison. Additionally, $let aids in avoiding repetition of expressions.

Another illustration:

{ 
  "_id": 1,
  "data": [
     { "name": "c", "value": 1 },
     { "name": "b", "value": 2 },
     { "name": "a", "value": 3 }
  ]
},
{ 
  "_id": 2, 
  "data": [
    { "name": "a", "value": 3 },
    { "name": "b", "value": 2 },
    { "name": "c", "value": 1 }
  ]
}

And the respective query:

db.collection.aggregate([
  { "$redact": {
     "$cond": {
       "if": { 
         "$let": {
           "vars": { 
             "data": { 
               "$map": {
                 "input": "$data",
                 "as": "el",
                 "in": "$$el.value"
               }
             }
           },
           "in": {
             "$lt": [
               { "$arrayElemAt": [ "$$data", -1 ] },
               { "$arrayElemAt": [ "$$data", -2 ] }
             ]
           }
         }
       },
       "then": "$$KEEP",
       "else": "$$PRUNE"
     }
  }}
])

Ensuring extraction of the "property" value plays a crucial role here due to potential discrepancies when comparing Object values directly against other array elements.

While $where remains available for older MongoDB versions or alternate approaches, it involves JavaScript evaluation which impacts performance compared to using native aggregation framework operators.

Prior versions may still support achieving this through the aggregation framework, but such methods are discouraged due to lower efficiency. It typically entails manipulating array elements to derive comparisons between subsequent items, resulting in increased processing time:

db.collection.aggregate([
    // Unwind array
    { "$unwind": "$data" },

    // Group back and get $last
    { "$group": {
        "_id": "$_id",
        "data": { "$push": "$data" },
        "lastData": { "$last" "$data" }
    }},
    // Unwind again
    { "$unwind": "$data" },
    // Compare to mark the last element
    { "$project": {
        "data": 1,
        "lastData": 1,
        "seen": { "$eq": [ "$lastData", "$data" ] }
    }},
    // Filter the previous $last from the list
    { "$match": { "seen": false } },
    // Group back and compare values
    { "$group": {
        "_id": "$_id",
        "data": { "$push": "$data" },
        "lastData": { "$last": "$lastData" },
        "secondLastData": { "$last": "$data" },
        "greater": {
            "$last": { "$lt": [ "$data.value", "$lastData.value" ] } 
        }
    }},
    // Filter to return only true
    { "$match": { "greater": true } }
 ])

Conversely, employing $where proves cleaner and more efficient for scenarios involving earlier MongoDB versions that necessitate further aggregation operations post-condition matching. 

Hence, transitioning to recent MongoDB releases and leveraging $redact along with logical comparisons in a singular pipeline stage yields enhanced performance by minimizing processing stages.

Answer №2

If you have MongoDB 3.2, the aggregation framework can be utilized to retrieve IDs of documents that match specific criteria. Once you have these IDs, you can then process them as needed.

For instance:

db.collection.aggregate([
  {$project:{
    cond :{$cond:[{
      $gt:[{
        $slice:["$v", -2,1]
       }, {
        $slice:["$v", -1,1]
       }]
      }, true, false]
    }}
  },
  {$match:{cond: true}}
])

In my collection, I have the following documents:

{ 
    "_id" : ObjectId("57094622b08be16cf12fcf6f"), 
    "v" : [
        1.0, 
        2.0, 
        3.0, 
        4.0, 
        8.0, 
        7.0
    ]
}
{ 
    "_id" : ObjectId("5709462bb08be16cf12fcf70"), 
    "v" : [
        1.0, 
        2.0, 
        3.0, 
        4.0, 
        8.0, 
        10.0
    ]
}

Based on your specified conditions, you are looking to select a document where the last element in the array is less than the second-to-last element. Therefore, it should identify the document with

_id = ObjectId("57094622b08be16cf12fcf6f")

The result of running the aggregation query will show:

{ 
    "_id" : ObjectId("57094622b08be16cf12fcf6f"), 
    "cond" : true
}

This outcome aligns with what we expected.

As mentioned earlier, you can iterate through the retrieved information and carry out any necessary actions, such as fetching the complete document.

Note: If your document is straightforward, projecting fields may eliminate the need for cursor iteration to fetch the complete document. However, in this example, I am assuming the document is complex and lacks upfront information about its properties or attributes.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Refreshing the page causes ngRoute to malfunction or results in an unknown route error

I am encountering an issue with my code. Whenever I refresh the page on localhost:portnumber/home or /todos or /contacts, it crashes -> showing an error "Cannot GET /home" or /todos or /contacts. The same problem occurs if I just enter localhost:port ...

Place a new button at the bottom of the react-bootstrap-typeahead dropdown menu for additional functionality

Currently, I have successfully implemented the React Bootstrap Typeahead with the desired options which is a good start. Now, my next challenge is to integrate a custom button at the end of the dropdown list for performing a specific action that is not ne ...

Eliminate the need for background video buffering

I have a piece of code that I'm using to remove all the created players for my video elements. The code works fine, but I'm facing an issue where the video keeps buffering in the background after it's changed via an ajax call success. Can yo ...

Differences between HTTP request errors and response errors(Note: This

Currently, I am researching $http interceptors and noticed that there are requestError and responseError functions available. 1) Can you explain the distinction between requestError and responseError? 2) Under what circumstances does requestError get t ...

Using regular expressions in JavaScript to work with numbers separated by commas, as well as their comparison operators such as greater than, greater than or

Currently, I have implemented this Regex pattern to validate numbers with decimals (comma separated) /(^\d*\,?\d*[1-9]+\d*$)|(^[1-9]+\d*\,\d*$)/ However, I am now faced with the need to modify it in order to also valida ...

I'm encountering an issue with Regex.test

When working with the following JavaScript code... $.post(url, data, function (json) { var patt = new RegExp('/^\[{"dID":/'); if (patt.test(json)) { //output json results formatted } else { //error so o ...

Styling a Pie or Doughnut Chart with CSS

I am working on creating a doughnut chart with rounded segments using Recharts, and I want it to end up looking similar to this: Although I have come close to achieving the desired result, I am encountering some issues: Firstly, the first segment is over ...

Node.js post request body is still showing as undefined despite using body-parser

Hello everyone, I am currently using Node.js to implement a Dialogflow chatbot. My goal is to extract parameters from an HTTP POST request. To achieve this, I utilized Postman and made sure to set the content type to JSON in the header. Below is the code f ...

Searching for geospatial indexes on Azure CosmosDB (DocumentDB) with the Mongo API does not yield results

My Azure CosmosDB contains a collection named restaurants with a field geoJSON that specifies the location of each restaurant in geoJSON format. I am using the MongoDB API for accessing this data. Upon logging into the DB through the mongo shell, I can vi ...

Hide popup in React Semantic UI when clicking on a different popup

I've integrated React Semantic UI into my application and I'm using the semantic Popup component to display tooltips. One issue I'm encountering is that when I click on a popup button, previously opened popups are not automatically closing. ...

Vulnerability protection against AngularJS JSON is not removed

I am currently working on an Angular app that communicates with an API. The JSON responses from the API are prefixed with )]}', as recommended in Angular's official documentation. The issue I am facing is that my browser seems to try decoding th ...

Is there a way to utilize regular expressions in React to dynamically insert onclick events into specific words within a text block?

I've been experimenting with regular expressions in React to implement an onclick event for each word in a text. I've attempted two different strategies, but neither has been successful thus far. Initially, I tried: return( <div> & ...

bootstrap-vue tabs - reveal specific tab content based on URL anchor tag

For my SPA, I am utilizing bootstrap-vue and currently working on a page where nested content needs to be placed within b-tabs. If given a URL with an anchor (e.g. www.mydomain.com/page123#tab-3), the goal is to display the content under Tab 3. Query: Ho ...

The ideal scenarios for employing functional setState

Lately, I've been delving into the world of React, immersing myself in tutorials and explanations on how to manipulate elements in different ways. One aspect that has caught my interest is the setState function, which allows you to update or override ...

Ajax response data triggered twice

I'm struggling to understand why my data is being called twice. I attempted to replace 'append', but it's not working. I suspect the issue lies within my controller. Here is my Ajax call: jQuery(document).ready(function($) { $('# ...

Disregard Cloudflare's Automatic RocketLoader feature for certain JavaScript scripts

After extensive research and failed attempts, I am seeking help to disable Cloudflare Rocketloader for a specific JavaScript file on my WordPress website. Specifically, I need to exclude the Automatic Rocket Loader for a particular .js file. I attempted t ...

To avoid TS2556 error in TypeScript, make sure that a spread argument is either in a tuple type or is passed to a rest parameter, especially when using

So I'm working with this function: export default function getObjectFromTwoArrays(keyArr: Array<any>, valueArr: Array<any>) { // Beginning point: // [key1,key2,key3], // [value1,value2,value3] // // End point: { // key1: val ...

Obtain the height and width of the original images from the href and assign them to your attributes using jQuery

Hey there pals, I'm currently on a mission to fetch the dimensions (height and width) of an image from a hyperlink and then insert those values into its attribute. This task has got me going bonkers! Here's my snippet: <figure> <a ...

ReactJS - What makes ReactJS unique compared to other technologies?

Hey there! I'm currently trying to figure out why this specific code snippet was successful while my previous one wasn't. I've included both snippets below: SUCCESSFUL CODE: handleInputChange = (e) => { let { value } = e.target; ...

React Router integration problem with Semantic UI React

Just diving into ReactJS and encountering a problem with using "Menu.Item" (from Semantic UI React) and React Router. I won't include my imports here, but rest assured they are all set up correctly. The constructor in my "App.jsx" looks like this: ...