@@ -1562,6 +1562,7 @@ public function upsertDocuments(Document $collection, string $attribute, array $
15621562 $ operations = [];
15631563 foreach ($ changes as $ change ) {
15641564 $ document = $ change ->getNew ();
1565+ $ oldDocument = $ change ->getOld ();
15651566 $ attributes = $ document ->getAttributes ();
15661567 $ attributes ['_uid ' ] = $ document ->getId ();
15671568 $ attributes ['_createdAt ' ] = $ document ['$createdAt ' ];
@@ -1587,6 +1588,9 @@ public function upsertDocuments(Document $collection, string $attribute, array $
15871588
15881589 unset($ record ['_id ' ]); // Don't update _id
15891590
1591+ // Get fields to unset for schemaless mode
1592+ $ unsetFields = $ this ->getUpsertAttributeRemovals ($ oldDocument , $ document , $ record );
1593+
15901594 if (!empty ($ attribute )) {
15911595 // Get the attribute value before removing it from $set
15921596 $ attributeValue = $ record [$ attribute ] ?? 0 ;
@@ -1595,17 +1599,28 @@ public function upsertDocuments(Document $collection, string $attribute, array $
15951599 // it is requierd to mimic the behaver of SQL on duplicate key update
15961600 unset($ record [$ attribute ]);
15971601
1602+ // Also remove from unset if it was there
1603+ unset($ unsetFields [$ attribute ]);
1604+
15981605 // Increment the specific attribute and update all other fields
15991606 $ update = [
16001607 '$inc ' => [$ attribute => $ attributeValue ],
16011608 '$set ' => $ record
16021609 ];
1610+
1611+ if (!empty ($ unsetFields )) {
1612+ $ update ['$unset ' ] = $ unsetFields ;
1613+ }
16031614 } else {
16041615 // Update all fields
16051616 $ update = [
16061617 '$set ' => $ record
16071618 ];
16081619
1620+ if (!empty ($ unsetFields )) {
1621+ $ update ['$unset ' ] = $ unsetFields ;
1622+ }
1623+
16091624 // Add UUID7 _id for new documents in upsert operations
16101625 if (empty ($ document ->getSequence ())) {
16111626 $ update ['$setOnInsert ' ] = [
@@ -1634,6 +1649,43 @@ public function upsertDocuments(Document $collection, string $attribute, array $
16341649 return \array_map (fn ($ change ) => $ change ->getNew (), $ changes );
16351650 }
16361651
1652+ /**
1653+ * Get fields to unset for schemaless upsert operations
1654+ *
1655+ * @param Document $oldDocument
1656+ * @param Document $newDocument
1657+ * @param array<string, mixed> $record
1658+ * @return array<string, string>
1659+ */
1660+ private function getUpsertAttributeRemovals (Document $ oldDocument , Document $ newDocument , array $ record ): array
1661+ {
1662+ $ unsetFields = [];
1663+
1664+ if ($ this ->getSupportForAttributes () || $ oldDocument ->isEmpty ()) {
1665+ return $ unsetFields ;
1666+ }
1667+
1668+ $ oldUserAttributes = $ oldDocument ->getAttributes ();
1669+ $ newUserAttributes = $ newDocument ->getAttributes ();
1670+
1671+ $ protectedFields = ['_uid ' , '_id ' , '_createdAt ' , '_updatedAt ' , '_permissions ' , '_tenant ' ];
1672+
1673+ foreach ($ oldUserAttributes as $ originalKey => $ originalValue ) {
1674+ if (in_array ($ originalKey , $ protectedFields ) || array_key_exists ($ originalKey , $ newUserAttributes )) {
1675+ continue ;
1676+ }
1677+
1678+ $ transformed = $ this ->replaceChars ('$ ' , '_ ' , [$ originalKey => $ originalValue ]);
1679+ $ dbKey = array_key_first ($ transformed );
1680+
1681+ if ($ dbKey && !array_key_exists ($ dbKey , $ record ) && !in_array ($ dbKey , $ protectedFields )) {
1682+ $ unsetFields [$ dbKey ] = '' ;
1683+ }
1684+ }
1685+
1686+ return $ unsetFields ;
1687+ }
1688+
16371689 /**
16381690 * Get sequences for documents that were created
16391691 *
@@ -2067,6 +2119,10 @@ private function getMongoTypeCode(string $appwriteType): string
20672119 {
20682120 return match ($ appwriteType ) {
20692121 Database::VAR_STRING => 'string ' ,
2122+ Database::VAR_VARCHAR => 'string ' ,
2123+ Database::VAR_TEXT => 'string ' ,
2124+ Database::VAR_MEDIUMTEXT => 'string ' ,
2125+ Database::VAR_LONGTEXT => 'string ' ,
20702126 Database::VAR_INTEGER => 'int ' ,
20712127 Database::VAR_FLOAT => 'double ' ,
20722128 Database::VAR_BOOLEAN => 'bool ' ,
@@ -2694,6 +2750,17 @@ public function getLimitForString(): int
26942750 return 2147483647 ;
26952751 }
26962752
2753+ /**
2754+ * Get max VARCHAR limit
2755+ * MongoDB doesn't distinguish between string types, so using same as string limit
2756+ *
2757+ * @return int
2758+ */
2759+ public function getMaxVarcharLength (): int
2760+ {
2761+ return 2147483647 ;
2762+ }
2763+
26972764 /**
26982765 * Get max INT limit
26992766 *
0 commit comments