1010import io .github .thunderz99 .cosmos .*;
1111import io .github .thunderz99 .cosmos .condition .Aggregate ;
1212import io .github .thunderz99 .cosmos .condition .Condition ;
13+ import io .github .thunderz99 .cosmos .dto .BulkPatchOperation ;
1314import io .github .thunderz99 .cosmos .dto .CosmosBatchResponseWrapper ;
1415import io .github .thunderz99 .cosmos .dto .CosmosBulkResult ;
1516import io .github .thunderz99 .cosmos .dto .CosmosSqlQuerySpec ;
@@ -36,7 +37,8 @@ public class CosmosDatabaseImpl implements CosmosDatabase {
3637
3738 private static Logger log = LoggerFactory .getLogger (CosmosDatabaseImpl .class );
3839
39- static final int MAX_BATCH_NUMBER_OF_OPERATION = 100 ;
40+ static final int MAX_BATCH_NUMBER_OF_OPERATION = CosmosLimits .BATCH_OPERATION_LIMIT ;
41+ static final int BULK_PATCH_CHUNK_SIZE = CosmosLimits .BULK_CHUNK_SIZE ;
4042
4143 static final int FIND_PREFERRED_PAGE_SIZE = 10 ;
4244
@@ -1279,6 +1281,85 @@ public CosmosBulkResult bulkDelete(String coll, List<?> data, String partition)
12791281 return result ;
12801282 }
12811283
1284+ /**
1285+ * Bulk patch documents with the same patch operations.
1286+ *
1287+ * @param coll collection name
1288+ * @param ids target document ids
1289+ * @param operations patch operations
1290+ * @param partition partition name
1291+ * @return CosmosBulkResult
1292+ * @throws Exception cosmos exception
1293+ */
1294+ public CosmosBulkResult bulkPatch (String coll , List <String > ids , PatchOperations operations , String partition ) throws Exception {
1295+ doCheckBeforeBulkPatch (coll , ids , operations , partition );
1296+
1297+ var partitionKey = new PartitionKey (partition );
1298+ var container = this .clientV4 .getDatabase (db ).getContainer (coll );
1299+
1300+ log .info ("begin bulkPatch(same operations) coll:{}, partition:{}, account:{}" , coll , partition , getAccount ());
1301+
1302+ var ret = new CosmosBulkResult ();
1303+ var retryList = new ArrayList <Object >();
1304+ for (int from = 0 ; from < ids .size (); from += BULK_PATCH_CHUNK_SIZE ) {
1305+ var to = Math .min (from + BULK_PATCH_CHUNK_SIZE , ids .size ());
1306+ var chunkIds = ids .subList (from , to );
1307+ var itemOperations = chunkIds .stream ()
1308+ .map (id -> CosmosBulkOperations .getPatchItemOperation (id , partitionKey , operations .getCosmosPatchOperations ()))
1309+ .collect (Collectors .toList ());
1310+
1311+ var chunkResult = RetryUtil .executeBulkWithRetry (coll , itemOperations ,
1312+ (ops ) -> container .executeBulkOperations (ops ));
1313+
1314+ ret .successList .addAll (chunkResult .successList );
1315+ ret .fatalList .addAll (chunkResult .fatalList );
1316+ retryList .addAll (chunkResult .retryList );
1317+ }
1318+ ret .retryList = retryList ;
1319+
1320+ log .info ("end bulkPatch(same operations) coll:{}, partition:{}, account:{}" , coll , partition , getAccount ());
1321+ return ret ;
1322+ }
1323+
1324+ /**
1325+ * Bulk patch documents.
1326+ * Note: Non-transaction. Have no number limit in theoretically.
1327+ *
1328+ * @param coll collection name
1329+ * @param data bulk patch operations (id + PatchOperations)
1330+ * @param partition partition name
1331+ * @return CosmosBulkResult
1332+ */
1333+ public CosmosBulkResult bulkPatch (String coll , List <BulkPatchOperation > data , String partition ) throws Exception {
1334+ doCheckBeforeBulkPatch (coll , data , partition );
1335+
1336+ var partitionKey = new PartitionKey (partition );
1337+ var container = this .clientV4 .getDatabase (db ).getContainer (coll );
1338+
1339+ log .info ("begin bulkPatch coll:{}, partition:{}, account:{}" , coll , partition , getAccount ());
1340+
1341+ var ret = new CosmosBulkResult ();
1342+ var retryList = new ArrayList <Object >();
1343+ for (int from = 0 ; from < data .size (); from += BULK_PATCH_CHUNK_SIZE ) {
1344+ var to = Math .min (from + BULK_PATCH_CHUNK_SIZE , data .size ());
1345+ var chunkData = data .subList (from , to );
1346+ var operations = chunkData .stream ()
1347+ .map (it -> CosmosBulkOperations .getPatchItemOperation (it .id , partitionKey , it .operations .getCosmosPatchOperations ()))
1348+ .collect (Collectors .toList ());
1349+
1350+ var chunkResult = RetryUtil .executeBulkWithRetry (coll , operations ,
1351+ (ops ) -> container .executeBulkOperations (ops ));
1352+
1353+ ret .successList .addAll (chunkResult .successList );
1354+ ret .fatalList .addAll (chunkResult .fatalList );
1355+ retryList .addAll (chunkResult .retryList );
1356+ }
1357+ ret .retryList = retryList ;
1358+
1359+ log .info ("end bulkPatch coll:{}, partition:{}, account:{}" , coll , partition , getAccount ());
1360+ return ret ;
1361+ }
1362+
12821363 @ Override
12831364 public boolean ping (String coll ) throws Exception {
12841365 var docs = this .find (coll , Condition .filter ().limit (1 ), "_ping" );
@@ -1290,10 +1371,37 @@ static void checkBatchMaxOperations(List<?> data) {
12901371 // There's a current limit of 100 operations per TransactionalBatch to ensure the performance is as expected and within SLAs:
12911372 // https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/transactional-batch?tabs=dotnet#limitations
12921373 if (data .size () > MAX_BATCH_NUMBER_OF_OPERATION ) {
1293- throw new IllegalArgumentException ("The number of data operations should not exceed 100." );
1374+ throw new IllegalArgumentException ("The number of data operations should not exceed %d." . formatted ( MAX_BATCH_NUMBER_OF_OPERATION ) );
12941375 }
12951376 }
12961377
1378+ static void doCheckBeforeBulkPatch (String coll , List <BulkPatchOperation > data , String partition ) {
1379+ Checker .checkNotBlank (coll , "coll" );
1380+ Checker .checkNotBlank (partition , "partition" );
1381+ Checker .checkNotEmpty (data , "bulkPatch data " + coll + " " + partition );
1382+
1383+ for (var operation : data ) {
1384+ Checker .checkNotNull (operation , "bulkPatch operation" );
1385+ Checker .checkNotBlank (operation .id , "bulkPatch operation id" );
1386+ checkValidId (operation .id );
1387+ Checker .checkNotNull (operation .operations , "bulkPatch operation patch operations" );
1388+ Preconditions .checkArgument (operation .operations .size () <= PatchOperations .LIMIT ,
1389+ "Size of operations should be less or equal to 10. We got: %d, which exceed the limit 10" ,
1390+ operation .operations .size ());
1391+ }
1392+ }
1393+
1394+ static void doCheckBeforeBulkPatch (String coll , List <String > ids , PatchOperations operations , String partition ) {
1395+ Checker .checkNotBlank (coll , "coll" );
1396+ Checker .checkNotBlank (partition , "partition" );
1397+ Checker .checkNotEmpty (ids , "bulkPatch ids " + coll + " " + partition );
1398+ Checker .checkNotNull (operations , "bulkPatch operations" );
1399+ Preconditions .checkArgument (operations .size () <= PatchOperations .LIMIT ,
1400+ "Size of operations should be less or equal to 10. We got: %d, which exceed the limit 10" ,
1401+ operations .size ());
1402+ checkValidId (ids );
1403+ }
1404+
12971405 /**
12981406 * Get cosmos db account id associated with this instance.
12991407 *
0 commit comments