Как удалить объект из массива и обновить значение позиции всех остальных объектов?

Среда

Родной драйвер Node
MongoDB 4.0.2

Желаемое поведение

Удалите объект из массива объектов на основе его id и уменьшите значение position другого объекта, где это возможно.

В частности, я пытаюсь:

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

Возможно, это может быть связано с использованием $inc и -1, но я все еще не уверен, как выполнить итерацию.

Что я пробовал

У меня есть логика, работающая для сценария JavaScript (работает в консоли браузера):

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");

Мне просто нужно перевести это в сценарий MongoDB/Node - пока у меня есть только часть удаления объекта:

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" });
        }
    });

}
1
0
77
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Обновлено согласно ответь здесь.

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
        }
    });

}

Должно ли свойство position в updateMany быть чем-то вроде: statements.position? Потому что объект вложен в массив statements?

user1063287 10.09.2018 08:48

Хм, я думаю, это обновление только одного объекта в массиве statements. updateMany () документы говорит об этом методе updates multiple documents within the collection based on the filter. Так что, возможно, это неправильный метод, поскольку он, похоже, не обновляет несколько объекты в массиве. Может мне просто надо сделать какой нибудь стандартный update(), где какой то multi определяется как true? Однако этот ответ делает вид, что это невозможно? : /

user1063287 10.09.2018 09:35

Хм, похоже, это заставляет запрос игнорировать $gt, и у объектов все обновлена ​​их позиция (даже объект в позиции 0 изменяется на позицию -1, если объект в позиции 2 удален). Сейчас я смотрю на этот обновленный ответ: stackoverflow.com/a/46054172 ... обновил ваш ответ тем, что у меня работает.

user1063287 10.09.2018 10:49

Другие вопросы по теме