user1063287
user1063287

Reputation: 10869

How to remove object from array and update all others objects position value?

Environment

Native Node driver
MongoDB 4.0.2

Desired Behaviour

Delete an object from an array of objects based on its id, and decrement other object's position value where applicable.

Specifically, I am trying to:

iterate over an array of objects in MongoDB and update a property in each object

Perhaps it might involve using $inc and -1 , but i'm still unsure how to do the iteration.

What I've Tried

I have the logic working for a JavaScript scenario (works in browser console):

function remove_and_update_position(id) {

    // faux array in collection document
    var statements = [{
            position: 0,  // < i want to update 'position' of all objects after an object is removed  
            id: "a"
        },
        {
            position: 1,
            id: "b"
        },
        {
            position: 2,
            id: "c"
        },
        {
            position: 3,
            id: "d"
        },
        {
            position: 4,
            id: "e"
        }

    ];

    // delete an object from the 'statements' array by its id
    statements.splice(statements.indexOf(statements.find(item => item.id == id)), 1);

    // iterate over the modified array
    for (var i = 0; i < statements.length; i++) {

        // for all objects in the modified array,  
        // with position numbers greater than the  
        // position removed ( minus 1),  
        // decrement their position numbers
        if (i > position - 1) {
            var new_position = statements[i].position - 1;
            statements[i].position = new_position;
        }

    }

    // verify adjustments were correct
    console.log(statements);

}

// call the function
remove_and_update_position("c");

I just need to translate it into a MongoDB/Node scenario - so far i just have the object removal part:

const remove_and_update_position = (req, res) => {

    var request_body = req.body;

    var topic_id = request_body.topic_id;

    var o_id = new ObjectID(topic_id);

    var collection = mongo_client.db("topics").collection("topics");

    var statement_id = request_body.statement_id; 

    var position = Number(request_body.position); 

    // query for the relevant document *and* target nested statement by id
    var filter = { _id: o_id, "statements.id": statement_id };

    // remove from statements array
    var update = { $pull: { "statements": { id: statement_id } } };

    // perform the update
    collection.updateOne(filter, update, function(err, doc) {
        if (err) {
            res.send(err);
        } else {
            res.json({ response_type: "success" });
        }
    });

}

Upvotes: 1

Views: 166

Answers (1)

tashakori
tashakori

Reputation: 2441

Updated per answer here.

const remove_and_update_position = (req, res) => {

    var request_body = req.body;

    var topic_id = request_body.topic_id;

    var o_id = new ObjectID(topic_id);

    var collection = mongo_client.db("topics").collection("topics");

    var statement_id = request_body.statement_id;

    var position = Number(request_body.position);

    // query for the relevant document *and* target nested statement by id
    var filter = { _id: o_id, "statements.id": statement_id };

    // remove from statements array
    var update = { $pull: { "statements": { id: statement_id } } };

    // perform the update
    collection.updateOne(filter, update, function(err, doc) {
        if (err) {
            res.send(err);
        } else {

            // BEGIN decrement others objects position
            var position_indicator = position - 1;

            console.log("deleted object position: " + position);
            console.log("will decrement objects with position greater than: " + position_indicator);

            var new_filter = { _id: o_id, "statements.position": { $gt: position_indicator } };

            var new_update = { $inc: { "statements.$[elem].position": -1 } };

            var array_filters = { "arrayFilters": [{ "elem.position": { $gt: position_indicator } }], "multi": true }; 

            collection.updateOne(new_filter, new_update, array_filters, function(err, doc) {
                if (err) {
                    res.send(err);
                } else {
                    res.json({ response_type: "success" });
                }
            });
            // END decrement others objects position
        }
    });

}

Upvotes: 1

Related Questions