Parcourir la source

Fix: MongoCollection::save should replace the whole document instead of only setting the given fields

Doing an update with $set will not remove fields, that are not present in the new document anymore.
Bastian Hofmann il y a 10 ans
Parent
commit
6b9c179bf3

+ 21 - 5
lib/Mongo/MongoCollection.php

@@ -719,16 +719,32 @@ class MongoCollection
         $id = $this->ensureDocumentHasMongoId($a);
 
         $document = (array) $a;
-        unset($document['_id']);
 
         $options['upsert'] = true;
 
-        $result = $this->update(['_id' => $id], ['$set' => $a], $options);
-        if ($result['ok'] == 0.0) {
-            throw new \MongoCursorException();
+        try {
+            /** @var \MongoDB\UpdateResult $result */
+            $result = $this->collection->replaceOne(
+                TypeConverter::fromLegacy(['_id' => $id]),
+                TypeConverter::fromLegacy($document),
+                $this->convertWriteConcernOptions($options)
+            );
+        } catch (\MongoDB\Driver\Exception\Exception $e) {
+            ExceptionConverter::toLegacy($e);
         }
 
-        return $result;
+        if (!$result->isAcknowledged()) {
+            return true;
+        }
+
+        return [
+            'ok' => 1.0,
+            'nModified' => $result->getModifiedCount(),
+            'n' => $result->getMatchedCount(),
+            'err' => null,
+            'errmsg' => null,
+            'updatedExisting' => $result->getUpsertedCount() == 0,
+        ];
     }
 
     /**

+ 18 - 0
tests/Alcaeus/MongoDbAdapter/MongoCollectionTest.php

@@ -618,6 +618,24 @@ class MongoCollectionTest extends TestCase
         $this->assertAttributeSame('foo', 'foo', $object);
     }
 
+    public function testSavingShouldReplaceTheWholeDocument() {
+        $id = '54203e08d51d4a1f868b456e';
+        $collection = $this->getCollection();
+
+        $insertDocument = ['_id' => new \MongoId($id), 'foo' => 'bar'];
+        $saveDocument = ['_id' => new \MongoId($id)];
+
+        $collection->insert($insertDocument);
+        $collection->save($saveDocument);
+
+        $newCollection = $this->getCheckDatabase()->selectCollection('test');
+        $this->assertSame(1, $newCollection->count());
+        $object = $newCollection->findOne();
+
+        $this->assertNotNull($object);
+        $this->assertObjectNotHasAttribute('foo', $object);
+    }
+
     public function testSaveDuplicate()
     {
         $collection = $this->getCollection();