Modify the value of a string array element in MongoDB by referencing the element itself

I am currently using an express application with mongodb as the database. The structure of my collection is displayed below.

The documents in the collection look like this:

{
    _id: 5caa266c58b170106ff17f40,
    title: "Test2 88 bulkWrite",
    last_save_date: 2019-04-07T17:08:25.149+00:00,
    created_by: "McufNwnQX8YXC0tNSa1fdbt9Tus2",
    stories: [ { story_id: "1", objects: [...] },
               { story_id: "2", objects: [...] },
               { story_id: "3", objects: [...] },
                ... 
             ]    
 }

My current challenge involves deleting a specific array element when a user clicks a button. For example, when the element {story_id: "2", objects: [...]} is deleted, I need to decrement all elements with a story_id greater than "2" by one (e.g., change "3" to "2", "4" to "3").

I have successfully achieved the deletion part, but I'm struggling with the second step. Below is the code snippet:

var storyId = ... (obtained from a request);
var intStoryId = parseInt(storyId);

var arrayOfHigherNumber = function() {
    var temp = [];
    if (intStoryId == 5) { return temp; }
    for (var i = intStoryId + 1; i <= 5; i++) {
        temp.push(i.toString());
    }
    return temp;
}

collection.bulkWrite([
// The following code successfully deletes the specified story_id entry
    { updateOne: {
        'filter': {'_id' : ObjectID(docId) },
        'update': { 
            '$pull': { 'stories': { 'story_id': storyId } }
        }
    }},
// This part does NOT work properly.
    { updateMany: {
        'filter': { '_id': ObjectID(docId), 'story_id': { '$in': arrayOfHigherNumber() } },
        'update': {
            '$set': { 'stories': { 'story_id': (parseInt('story_id', 10) - 1).toString() } 
         }
     }
   }}
])

I've been trying different approaches and methods for the past 24 hours, including using NumberInt, $int, $convert, and even aggregation pipelines, but without success. It seems like a simple task that should be easily accomplished, but unfortunately not. Please note that story_id is a string, which adds complexity to the operation since typical operators like $inc cannot be used straightforwardly.

EDIT

The solution provided by Anthony Winzlet is correct. However, I slightly modified the approach for my implementation.

This is how I handled it:

collection.findOneAndUpdate(
    { "_id": ObjectID(docId) },
    { "$pull": { "stories": { "story_id": storyId } } },
    { returnOriginal: false }
)
.then(function(story) {
    collection.findOneAndUpdate(
        { "_id": ObjectID(docId) },
        { "$set": {
            "stories": story.value.stories.map(a => {
                if (parseInt(a.story_id, 10) > parseInt(storyId, 10)) {
                    return { story_id: (parseInt(a.story_id, 10) - 1).toString(), objects: a.objects }
                } else {
                    return { story_id: a.story_id , objects: a.objects }
                }
            })
        }}
    )
    .then(function(result) {
        response.send(result);
        client.close();
    })
})

Answer №1

Enhance performance by replacing bulk query with two separate operations utilizing async await

const story = await collection.findOneAndUpdate(
  { "_id" : ObjectID( docId ) },
  { "$pull": { "stories": { "story_id": storyId } }},
  { "new": true }
)

const update = await collection.findOneAndUpdate(
  { "_id" : ObjectID( docId ) },
  { "$set": {
    "stories": story.stories.map((a, i) => { if (parseInt(a.story_id) > parseInt(story_id)) return { story_id: parseInt(a.story_id) + 1 }})
  }}
)

Answer №2

To achieve your desired result, consider using the following code snippet:

collection.updateMany({ story_id : { $gte : deletedElementNo } }, { $inc : { story_id: -1 } });

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

Is it possible to transfer data from a form to a block without needing to reload the entire page

Trying to figure out a way to transfer data from a form and save it to the database simultaneously on a single page. I am not quite sure how to accomplish this, but here is the code snippet that I have created: $("#formbutton").click(function(event) { ...

Steps for implementing a click event for a navigation drop-down using an HTML helper class

In my MVC 5 application, I have implemented a navigation dropdown. Here is the code snippet: <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="menu> Report ...

Ensuring JSON data protection when sending Ajax requests in JavaScript (for(;;);)

After extensive research, I have not been able to find the answer I'm looking for despite similar questions being asked. My query concerns the usage of for(;;); while(1); before an Ajax response outputs a JSON string. I am curious about how this tec ...

How about mixing up your backgrounds with an overlay effect for a unique look?

Hey there, I'm currently working on adding random backgrounds to my website through an overlay, but I've hit a roadblock when it comes to displaying them. Here is the code I'm working with: .css / .php #intro { background: ...

What is the best way to conceal a route within the Angular 2 router?

Currently, my setup involves using angular 2 with router 3.0.0-rc.1. In the tutorial I am following, there is a specific template that is used for navigation: ` <nav> <a routerLink="/crisis-center" routerLinkActive="active" [routerLink ...

Transmit information from MATLAB to a website hosted locally

I've built a MATLAB GUI that generates numerous plots. My goal now is to display these plots on a local website through an HTML/JS file. I'm thinking of transferring the data to my browser/website using a Client/Server approach and then plottin ...

Guide to integrating numerous product filters for an ECommerce platform using Spring Boot, JavaScript, Ajax, and MySql

Currently, I am developing an E-Commerce Web App using Spring Boot which includes a feature to add multiple product filters. The user can select checkboxes corresponding to their preferences for filtering or searching products from the store. However, I am ...

Using AJAX to retrieve version information via jQuery

I have a straightforward script that extracts the value of a textarea and sends it via AJAX. When I input "??" as the text, the output seems to be corrupted with strange values. However, when I log out the retrieved value before sending it, everything appe ...

What is the best way to ask users to allow pop-ups in any browser using React.js?

Currently, I am utilizing "@azure/msal-browser": "^2.1.0" in my React SPA hosted on Azure app service. Within my App.js file, I have implemented msalInstance.acquireTokenPopup(tokenRequest) to obtain an auth token. This action prompts a pop-up in the bro ...

Ways to refresh the cache after performing delete, update, or add operations on data

I currently utilize a data caching tool called cache-all. However, I have encountered an issue where newly added information does not appear when displaying all data after the addition. To ensure that new data is immediately reflected in requests, I typica ...

Images are not appearing when using ng-repeat

const createFullName = (first, last) => { return `${last}, ${first}`; }; let partyImage = ""; if(party=="R") { partyImage = "<img src='/images/r.png'>"; } else { partyImage = "<img src='/images/d.png'>"; } l ...

Save the expression or condition in the document

Recently, I've started working with mongodb and I'm struggling to determine if the following scenario is feasible. Is it possible to store a comparison condition, like gt or lt, inside a field of a document and then use it in a query? For examp ...

Is it possible for a MongoDB objectid to consist solely of numerical characters?

Is it possible for a MongoDB objectid to consist solely of numbers? In the library I am using, there is a snippet of code that performs the following check: if (is_int($mixed) || ctype_digit($mixed)) { return; } As a consequence, a record in my data ...

Ways to apply autofocus to one element once another element already has it?

I have encountered an issue while attempting to give a textarea autofocus using the autofocus attribute. Upon doing so, I receive an error message in the console that says: Autofocus processing was blocked because a document already has a focused element. ...

angular trustAsHtml does not automatically insert content

Two divs are present on the page. Upon clicking button1, an iframe is loaded into div1. The same applies to button2 and div2. These iframes are loaded via ajax and trusted using $sce.trustAsHtml. This is how the HTML looks: <div ng-bind-html="video.tru ...

Here is a step-by-step guide on how to use JavaScript to eliminate the page title, URL, date and

When printing a page using window.print, is there a way to exclude the page title, URL, page number, and date/time from appearing? ...

Implementing material-ui Snackbar as a global feature: a step-by-step guide

Currently, I'm in the process of building my react application using material-ui's Snackbar feature. With a plethora of components in my project, I prefer not to include <Snackbar/> in every single one of them. Is there a method to develop ...

Store data in Firebase Storage and retrieve the link to include it in Realtime Database

Utilizing Firebase Realtime Database and Firebase Storage for this application involves uploading images from the pictures array to Firebase Storage. The goal is to obtain the Firebase Storage link for each image, add it to the object pushed into imagesU ...

Is MongoDB unwind feature beneficial in find() queries? Can find() queries have improved performance?

I'm facing a challenge with my current aggregate query that's taking too long to fetch results. I specifically require the Aggregation framework due to the $unwind parameter as I need to query data within an array. Is there a way to refactor this ...

Is it possible to utilize the inline/hardcoded type declared in the component.d.ts file for reuse

Is there a way to pass props selectively to the library component? The library has hardcoded multiple values in an inline type. If my code needs to automatically update with any new additions to the library-defined type, can I reuse those inline values r ...