'In MongoDB, method to keep the previous value of a field in a different field while updating an object?

Say I have an object with field state, I want to update this field, while keeping the previous value of state in previous_state field. First, I have tried to make an update with unset-rename-set:

collection.update(query, {$unset: {previous_state: ""}, $rename: {state: "previous_state"}, $set: {state: value}})

no surprise it did not work. After reading:

I am nearly convinced that I do not have a solution to perform this in a single query. So the question is what is the best practice to do it?



Solution 1:[1]

One solution (if you've got onlty one writer) could be to trigger your update in two steps:

> var previousvalue = collection.findOne(query).state;
> collection.update(query, {$set: {"previous_state": previousvalue, "state": newstatevalue}});

Solution 2:[2]

There are various ways to do it, depending on the version of MongoDB, and they are described in this answer from another thread: https://stackoverflow.com/a/37280419/5538923 . For MongoDB 3.4+, for example, there is this query that can be put in MongoSH:

db.collection.aggregate(
[
    { "$addFields": { 
        "previous_state": { "$concat": [ "$state" ] },
        "state": { "$concat": [ "$state", " customly modified" ] } 
    }},
    { "$out": "collection" }
])

Also note that this query works only when the MongoDB instance is not sharded. When sharded (e.g., often the case in Microsoft Azure CosmosDB), the method described in that answer for MongoDB 3.2+ works, or alternatively put a new collection as destination (in the $out close), and then import the data in the original collection, after removing all the data there.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 marcor92