yiisoft / yii2-mongodb

Yii 2 MongoDB extension
http://www.yiiframework.com
BSD 3-Clause "New" or "Revised" License
327 stars 190 forks source link

Update MongoDB field using value of another field #352

Open zerg4000 opened 2 years ago

zerg4000 commented 2 years ago

Starting from MongoDB v4.2 we can Updates with Aggregation Pipeline (see https://www.mongodb.com/docs/manual/tutorial/update-documents-with-aggregation-pipeline/) But with yii2-mongodb query like this

Model::updateAll([
    ['$set' => ['new_field => '$old_field']]
]);

or this

$collection = Yii::$app->mongodb->getCollection('collectionName');        
$collection->update([], [['$set' =>  ['new_field => '$old_field']]]);

causes MongoDB Exception

What steps will reproduce the problem?

$collection = Yii::$app->mongodb->getCollection('collectionName');        
$collection->update([], [['$set' =>  ['new_field => '$old_field']]]);

What's expected?

Update all rows and add new field using value of another field

What do you get instead?

MongoDB Exception – yii\mongodb\Exception Modifiers operate on fields but we found type array instead. For example: {$mod: {: ...}} not {$set: [ { $set: { user_uid: "$owner" } } ]}

Additional info

I think problem in yii\mongodb\Command::addUpdate method and can fixed:

        if ($options['multi']) {
            $keys = array_keys($document);
            if (!empty($keys) && strncmp('$', $keys[0], 1) !== 0) {
                $document = ['$set' => $document];
            }
        }

change to

        if ($options['multi'] && \yii\helpers\ArrayHelper::isAssociative($document)) {
            $keys = array_keys($document);
            if (!empty($keys) && strncmp('$', $keys[0], 1) !== 0) {
                $document = ['$set' => $document];
            }
        }
Q A
Yii version 2.0.45
Yii MongoDB version 2.1.12
MongoDB server version 5.0.6
PHP version 8.1.7
Operating system Alpine Linux
samdark commented 2 years ago

Interesting. Do you have time to prepare a pull request with a fix and some tests?