Skip to content

Commit a0e7275

Browse files
committed
CDRIVER-2661 accept arrayFilters option for bulk update functions
1 parent 6972a0c commit a0e7275

File tree

7 files changed

+180
-9
lines changed

7 files changed

+180
-9
lines changed

build/generate-opts.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,19 @@ def __init__(self, items, **defaults):
211211
])),
212212

213213
('mongoc_bulk_update_one_opts_t', Struct(
214-
[('update', {'type': 'mongoc_bulk_update_opts_t'})],
214+
[
215+
('update', {'type': 'mongoc_bulk_update_opts_t'}),
216+
array_filters_option,
217+
],
215218
multi='false',
216219
validate='_mongoc_default_update_vflags',
217220
allow_extra=False)),
218221

219222
('mongoc_bulk_update_many_opts_t', Struct(
220-
[('update', {'type': 'mongoc_bulk_update_opts_t'})],
223+
[
224+
('update', {'type': 'mongoc_bulk_update_opts_t'}),
225+
array_filters_option,
226+
],
221227
multi='true',
222228
validate='_mongoc_default_update_vflags',
223229
allow_extra=False)),

src/libmongoc/doc/includes/bulk-update-many-opts.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
* ``bypassDocumentValidation``: Set to ``true`` to skip server-side schema validation of the provided BSON documents.
55
* ``collation``: Configure textual comparisons. See :ref:`Setting Collation Order <setting_collation_order>`, and `the MongoDB Manual entry on Collation <https://docs.mongodb.com/manual/reference/collation/>`_. Collation requires MongoDB 3.2 or later, otherwise an error is returned.
66
* ``upsert``: If true, insert a document if none match ``selector``.
7+
* ``arrayFilters``: An array of filters specifying to which array elements an update should apply.

src/libmongoc/doc/includes/bulk-update-one-opts.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
* ``bypassDocumentValidation``: Set to ``true`` to skip server-side schema validation of the provided BSON documents.
55
* ``collation``: Configure textual comparisons. See :ref:`Setting Collation Order <setting_collation_order>`, and `the MongoDB Manual entry on Collation <https://docs.mongodb.com/manual/reference/collation/>`_. Collation requires MongoDB 3.2 or later, otherwise an error is returned.
66
* ``upsert``: If true, insert a document if none match ``selector``.
7+
* ``arrayFilters``: An array of filters specifying to which array elements an update should apply.

src/libmongoc/src/mongoc/mongoc-bulk-operation.c

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,8 @@ _mongoc_bulk_operation_update_append (
394394
mongoc_bulk_operation_t *bulk,
395395
const bson_t *selector,
396396
const bson_t *document,
397-
const mongoc_bulk_update_opts_t *update_opts)
397+
const mongoc_bulk_update_opts_t *update_opts,
398+
const bson_t *extra_opts)
398399
{
399400
mongoc_write_command_t command = {0};
400401
mongoc_write_command_t *last;
@@ -410,6 +411,10 @@ _mongoc_bulk_operation_update_append (
410411
bson_append_document (&opts, "collation", 9, &update_opts->collation);
411412
}
412413

414+
if (extra_opts) {
415+
bson_concat (&opts, extra_opts);
416+
}
417+
413418
if (bulk->commands.len) {
414419
last = &_mongoc_array_index (
415420
&bulk->commands, mongoc_write_command_t, bulk->commands.len - 1);
@@ -438,6 +443,7 @@ _mongoc_bulk_operation_update_with_opts (
438443
const bson_t *selector,
439444
const bson_t *document,
440445
const mongoc_bulk_update_opts_t *update_opts,
446+
const bson_t *extra_opts,
441447
bool multi,
442448
bson_error_t *error) /* OUT */
443449
{
@@ -463,7 +469,8 @@ _mongoc_bulk_operation_update_with_opts (
463469
RETURN (false);
464470
}
465471

466-
_mongoc_bulk_operation_update_append (bulk, selector, document, update_opts);
472+
_mongoc_bulk_operation_update_append (
473+
bulk, selector, document, update_opts, extra_opts);
467474

468475
RETURN (true);
469476
}
@@ -488,8 +495,18 @@ mongoc_bulk_operation_update_one_with_opts (mongoc_bulk_operation_t *bulk,
488495
RETURN (false);
489496
}
490497

491-
ret = _mongoc_bulk_operation_update_with_opts (
492-
bulk, selector, document, &update_opts.update, false /* multi */, error);
498+
if (!bson_empty (&update_opts.arrayFilters)) {
499+
bson_append_array (
500+
&update_opts.extra, "arrayFilters", 12, &update_opts.arrayFilters);
501+
}
502+
503+
ret = _mongoc_bulk_operation_update_with_opts (bulk,
504+
selector,
505+
document,
506+
&update_opts.update,
507+
&update_opts.extra,
508+
false /* multi */,
509+
error);
493510

494511
_mongoc_bulk_update_one_opts_cleanup (&update_opts);
495512
RETURN (ret);
@@ -515,8 +532,18 @@ mongoc_bulk_operation_update_many_with_opts (mongoc_bulk_operation_t *bulk,
515532
RETURN (false);
516533
}
517534

518-
ret = _mongoc_bulk_operation_update_with_opts (
519-
bulk, selector, document, &update_opts.update, true /* multi */, error);
535+
if (!bson_empty (&update_opts.arrayFilters)) {
536+
bson_append_array (
537+
&update_opts.extra, "arrayFilters", 12, &update_opts.arrayFilters);
538+
}
539+
540+
ret = _mongoc_bulk_operation_update_with_opts (bulk,
541+
selector,
542+
document,
543+
&update_opts.update,
544+
&update_opts.extra,
545+
true /* multi */,
546+
error);
520547

521548
_mongoc_bulk_update_many_opts_cleanup (&update_opts);
522549
RETURN (ret);
@@ -619,7 +646,8 @@ mongoc_bulk_operation_replace_one_with_opts (mongoc_bulk_operation_t *bulk,
619646
GOTO (done);
620647
}
621648

622-
_mongoc_bulk_operation_update_append (bulk, selector, document, update_opts);
649+
_mongoc_bulk_operation_update_append (
650+
bulk, selector, document, update_opts, &repl_opts.extra);
623651
ret = true;
624652

625653
done:

src/libmongoc/src/mongoc/mongoc-opts-private.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,13 @@ typedef struct _mongoc_bulk_update_opts_t {
9595

9696
typedef struct _mongoc_bulk_update_one_opts_t {
9797
mongoc_bulk_update_opts_t update;
98+
bson_t arrayFilters;
9899
bson_t extra;
99100
} mongoc_bulk_update_one_opts_t;
100101

101102
typedef struct _mongoc_bulk_update_many_opts_t {
102103
mongoc_bulk_update_opts_t update;
104+
bson_t arrayFilters;
103105
bson_t extra;
104106
} mongoc_bulk_update_many_opts_t;
105107

src/libmongoc/src/mongoc/mongoc-opts.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,7 @@ _mongoc_bulk_update_one_opts_parse (
932932
bson_init (&mongoc_bulk_update_one_opts->update.collation);
933933
mongoc_bulk_update_one_opts->update.upsert = false;
934934
mongoc_bulk_update_one_opts->update.multi = false;
935+
bson_init (&mongoc_bulk_update_one_opts->arrayFilters);
935936
bson_init (&mongoc_bulk_update_one_opts->extra);
936937

937938
if (!opts) {
@@ -992,6 +993,15 @@ _mongoc_bulk_update_one_opts_parse (
992993
return false;
993994
}
994995
}
996+
else if (!strcmp (bson_iter_key (&iter), "arrayFilters")) {
997+
if (!_mongoc_convert_array (
998+
client,
999+
&iter,
1000+
&mongoc_bulk_update_one_opts->arrayFilters,
1001+
error)) {
1002+
return false;
1003+
}
1004+
}
9951005
else {
9961006
bson_set_error (error,
9971007
MONGOC_ERROR_COMMAND,
@@ -1009,6 +1019,7 @@ void
10091019
_mongoc_bulk_update_one_opts_cleanup (mongoc_bulk_update_one_opts_t *mongoc_bulk_update_one_opts)
10101020
{
10111021
bson_destroy (&mongoc_bulk_update_one_opts->update.collation);
1022+
bson_destroy (&mongoc_bulk_update_one_opts->arrayFilters);
10121023
bson_destroy (&mongoc_bulk_update_one_opts->extra);
10131024
}
10141025

@@ -1027,6 +1038,7 @@ _mongoc_bulk_update_many_opts_parse (
10271038
bson_init (&mongoc_bulk_update_many_opts->update.collation);
10281039
mongoc_bulk_update_many_opts->update.upsert = false;
10291040
mongoc_bulk_update_many_opts->update.multi = true;
1041+
bson_init (&mongoc_bulk_update_many_opts->arrayFilters);
10301042
bson_init (&mongoc_bulk_update_many_opts->extra);
10311043

10321044
if (!opts) {
@@ -1087,6 +1099,15 @@ _mongoc_bulk_update_many_opts_parse (
10871099
return false;
10881100
}
10891101
}
1102+
else if (!strcmp (bson_iter_key (&iter), "arrayFilters")) {
1103+
if (!_mongoc_convert_array (
1104+
client,
1105+
&iter,
1106+
&mongoc_bulk_update_many_opts->arrayFilters,
1107+
error)) {
1108+
return false;
1109+
}
1110+
}
10901111
else {
10911112
bson_set_error (error,
10921113
MONGOC_ERROR_COMMAND,
@@ -1104,6 +1125,7 @@ void
11041125
_mongoc_bulk_update_many_opts_cleanup (mongoc_bulk_update_many_opts_t *mongoc_bulk_update_many_opts)
11051126
{
11061127
bson_destroy (&mongoc_bulk_update_many_opts->update.collation);
1128+
bson_destroy (&mongoc_bulk_update_many_opts->arrayFilters);
11071129
bson_destroy (&mongoc_bulk_update_many_opts->extra);
11081130
}
11091131

src/libmongoc/tests/test-mongoc-bulk.c

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,111 @@ test_update_with_opts_validate (void)
871871
}
872872

873873

874+
/* Tests that documents in `coll` found with `selector` all match `match` */
875+
static void
876+
_test_docs_in_coll_matches (mongoc_collection_t *coll,
877+
bson_t *selector,
878+
const char *match,
879+
uint32_t expected_count)
880+
{
881+
const bson_t *next_doc;
882+
mongoc_cursor_t *cursor =
883+
mongoc_collection_find_with_opts (coll, selector, NULL, NULL);
884+
while (expected_count > 0) {
885+
ASSERT (mongoc_cursor_next (cursor, &next_doc));
886+
if (match) {
887+
ASSERT_MATCH (next_doc, match);
888+
}
889+
--expected_count;
890+
}
891+
ASSERT_CMPINT (expected_count, ==, 0);
892+
mongoc_cursor_destroy (cursor);
893+
}
894+
895+
896+
static void
897+
test_update_arrayfilters (void *ctx)
898+
{
899+
mongoc_client_t *client;
900+
mongoc_collection_t *collection;
901+
bson_t opts = BSON_INITIALIZER;
902+
mongoc_bulk_operation_t *bulk;
903+
904+
bson_error_t err;
905+
bson_t reply;
906+
bool ret = false;
907+
int i;
908+
909+
client = test_framework_client_new ();
910+
BSON_ASSERT (client);
911+
912+
collection = get_test_collection (client, "test_update_arrayfilters");
913+
BSON_ASSERT (collection);
914+
915+
mongoc_collection_drop (collection, NULL);
916+
917+
bson_append_bool (&opts, "ordered", 7, true);
918+
bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts);
919+
BSON_ASSERT (bulk);
920+
921+
for (i = 1; i < 4; i++) {
922+
ret = mongoc_bulk_operation_insert_with_opts (
923+
bulk,
924+
tmp_bson ("{'_id': %d, 'a': [{'x':1}, {'x':2}]}", i),
925+
NULL,
926+
&err);
927+
ASSERT_OR_PRINT (ret, err);
928+
}
929+
930+
ret = mongoc_bulk_operation_update_one_with_opts (
931+
bulk,
932+
tmp_bson ("{'_id': 1}"),
933+
tmp_bson ("{'$set': {'a.$[i].x': 3}}"),
934+
tmp_bson ("{'arrayFilters': [{'i.x': {'$gt': 1}}]}"),
935+
&err);
936+
ASSERT_OR_PRINT (ret, err);
937+
938+
ret = mongoc_bulk_operation_update_many_with_opts (
939+
bulk,
940+
tmp_bson ("{'_id': {'$gt': 1}}"),
941+
tmp_bson ("{'$set': {'a.$[i].x': 4}}"),
942+
tmp_bson ("{'arrayFilters': [{'i.x': {'$gt': 1}}]}"),
943+
&err);
944+
ASSERT_OR_PRINT (ret, err);
945+
946+
ASSERT_OR_PRINT ((bool) mongoc_bulk_operation_execute (bulk, &reply, &err),
947+
err);
948+
949+
ASSERT_MATCH (&reply,
950+
"{'nInserted': 3,"
951+
" 'nMatched': 3,"
952+
" 'nModified': 3,"
953+
" 'nRemoved': 0,"
954+
" 'nUpserted': 0,"
955+
" 'upserted': {'$exists': false},"
956+
" 'writeErrors': []}");
957+
bson_destroy (&reply);
958+
959+
ASSERT_COUNT (3, collection);
960+
961+
_test_docs_in_coll_matches (
962+
collection, tmp_bson ("{'_id':1}"), "{'a': [{'x':1}, {'x':3}]}", 1);
963+
964+
_test_docs_in_coll_matches (
965+
collection, tmp_bson ("{'_id':2}"), "{'a': [{'x':1}, {'x':4}]}", 1);
966+
967+
_test_docs_in_coll_matches (
968+
collection, tmp_bson ("{'_id':3}"), "{'a': [{'x':1}, {'x':4}]}", 1);
969+
970+
ASSERT_OR_PRINT (mongoc_collection_drop (collection, &err), err);
971+
972+
mongoc_bulk_operation_destroy (bulk);
973+
bson_destroy (&opts);
974+
mongoc_collection_destroy (collection);
975+
mongoc_client_destroy (client);
976+
}
977+
978+
874979
static void
875980
test_replace_one (bool ordered)
876981
{
@@ -4479,6 +4584,12 @@ test_bulk_install (TestSuite *suite)
44794584
TestSuite_AddLive (suite,
44804585
"/BulkOperation/update_with_opts_validate",
44814586
test_update_with_opts_validate);
4587+
TestSuite_AddFull (suite,
4588+
"/BulkOperation/update_arrayfilters",
4589+
test_update_arrayfilters,
4590+
NULL,
4591+
NULL,
4592+
test_framework_skip_if_max_wire_version_less_than_6);
44824593
TestSuite_AddLive (
44834594
suite, "/BulkOperation/replace_one_ordered", test_replace_one_ordered);
44844595
TestSuite_AddLive (suite,

0 commit comments

Comments
 (0)