Search code examples
mongodbpymongo

MongoDB Update: push old field value to another array field if new value is different


I have a simple collection like:

{
    "_id": "62e92e47e0f473e37a491574",
    "id": 1,
    "price": 999,
    "price_changed": false,
    "prices_history": [] # there cases when this field does not exist
}

I want to make an update statement (using pymongo) with price = 1000, so the final document looks like

{
    "_id": "62e92e47e0f473e37a491574",
    "id": 1,
    "price": 1000,
    "price_changed": true,
    "prices_history": [999]
}

So far I can only detect field value change with:

ops = [pymongo.UpdateOne(
        {'id': 1},
        [
            {
                '$set':
                    {
                        'id': 1,
                        'price': 1000,
                        'price_changed': {'$ne': ['$price', 1000]},
                    }
            }
        ]
    )]
    collection.bulk_write(ops)

But I cannot understand how to build the pipeline to add the last stage - push old value to the prices_history array

Any suggestions?

Cases:

Insert happens - should be inserted with prices_history = []

Update happens, values are equal - prices_history = prices_history

Update happens, values are different - prices_history = prices_history + price (old)


Solution

  • You can use $concatArrays operator to add new element in array, and $ifNull operator if the field prices_history does not exists,

    [
      {
        '$set': {
          'price': 1000,
          'price_changed': { '$ne': ['$price', 1000] },
          'prices_history': { 
            '$concatArrays': [
              { "$ifNull": ["$prices_history", []] }, 
              ["$price"]
            ] 
          }
        }
      }
    ]
    

    Playground