简体   繁体   中英

$push and $set in same update query with condition $cond pymongo mongodb

I'm trying to update my collection

For the single, object need to update the status and updated time.

Input object id as id new status as current status

Condition If the new status is different from the status in DB, then need to $push new status and timestamp into activity_log array. And update the update the updated_time and status of the record.

If the new status and previous status is same then updated_time will be updated.

Is it possible to do that in pymongo using single update?

collection.update({
        '_id': ObjectId(id),
    }, {
        '$cond': {
            'if': {
                'status': {
                    '$ne': current_status
                }
            },
            'then': {
                '$push': {
                    'activity_log': {
                        'status': current_status,
                        'changed_time': datetime.now()
                    }
                }
            },
            'else': None
        },
        '$set': {
            'status': current_status,
            'updated_time': datetime.now()
        }
    })

You can do that in a single query, From MongoDB 4.2 update query supports aggregation pipeline , You can do that as per below code

collection.update(
     {'_id': ObjectId(id)}, 
     [{'$set': {
            'status': current_status,
            'updated_time': datetime.now(),
            'activity_log':{
              '$cond': {
                'if': {'$ne': ['$status',current_status]},
                'then': {$concatArrays:['$activity_log',[
                          {
                           'status': current_status,
                           'changed_time': datetime.now()
                          }
                ]]},
                'else': '$activity_log'
            }
      }}}]
)

The $cond operator is not flow control like if-then-else, it is an expression that returns a value.

If you want to conditionally update a field based on the value of another field in the same document, you can use the pipeline form of update, assigning the field the result of the $cond expression.

collection.update(
     {'_id': ObjectId(id)}, 
     [{'$set': {
            'status': current_status,
            'updated_time': datetime.now(),
            'activity_log':{
              '$cond': {
                'if': {'$ne': ['$status',current_status]}
                'then': {$concatArrays:['$activity_log',[
                          {
                           'status': current_status,
                           'changed_time': datetime.now()
                          }
                ]]},
                'else': '$activity_log'
            }
      }}]
)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM