From eb4ad71cc91613ce8c4c8043e425a206907f3a8b Mon Sep 17 00:00:00 2001 From: Joel Lord Date: Mon, 24 Jan 2022 06:02:52 -0500 Subject: [PATCH] Adding support for arrayFilters in updates This PR is for the feature request [#4247](https://github.com/realm/realm-js/issues/4247). This PR adds support for arrayFilters by passing the arrayFilters parameter to the Realm serverless function. Additional testing was added to cover the case of an update with arrayFilters. --- docs/sync.js | 4 +++ lib/mongo-client.js | 2 ++ .../src/remote-mongodb-service.test.ts | 28 +++++++++++++++++++ .../MongoDBService/MongoDBCollection.ts | 2 ++ types/services.d.ts | 4 +++ 5 files changed, 40 insertions(+) diff --git a/docs/sync.js b/docs/sync.js index 389a74191d0..6785b332fb6 100644 --- a/docs/sync.js +++ b/docs/sync.js @@ -1279,6 +1279,8 @@ class MongoDBCollection { * @param {object} [options] Additional options to apply. * @param {boolean} [options.upsert=false] if true, indicates that MongoDB should insert a new document that matches the * query filter when the query does not match any existing documents in the collection. + * @param {object[]} [options.arrayFilters=false] if provided, indicates the arrayFilters to use to update + * an embedded array * @returns {Promise} */ updateOne(filter, update, options) {} @@ -1291,6 +1293,8 @@ class MongoDBCollection { * @param {object} [options] Additional options to apply. * @param {boolean} [options.upsert=false] if true, indicates that MongoDB should insert a new document that matches the * query filter when the query does not match any existing documents in the collection. + * @param {object[]} [options.arrayFilters=false] if provided, indicates the arrayFilters to use to update + * an embedded array * @returns {Promise} */ updateMany(filter, update, options) {} diff --git a/lib/mongo-client.js b/lib/mongo-client.js index 06021fb879e..d23d556fed8 100644 --- a/lib/mongo-client.js +++ b/lib/mongo-client.js @@ -183,6 +183,7 @@ class MongoDBCollection { query: filter, update, upsert: options.upsert, + arrayFilters: options.arrayFilters, }); } @@ -194,6 +195,7 @@ class MongoDBCollection { query: filter, update, upsert: options.upsert, + arrayFilters: options.arrayFilters, }); } diff --git a/packages/realm-web-integration-tests/src/remote-mongodb-service.test.ts b/packages/realm-web-integration-tests/src/remote-mongodb-service.test.ts index 0194ce1fce9..f50199dc366 100644 --- a/packages/realm-web-integration-tests/src/remote-mongodb-service.test.ts +++ b/packages/realm-web-integration-tests/src/remote-mongodb-service.test.ts @@ -293,6 +293,34 @@ describe("Remote MongoDB", () => { expect(result.modifiedCount).equals(3); }); + it("can update documents using array filters", async () => { + const collection = getCollection(); + // Insert a document with an embedded array + const insertResult = await collection.insertOne([ + { runId, name: "arrayFilter", values: [ {condition: 1, status: false}, {condition: 2, status: false} ] }, + ]); + expect(insertResult.insertedIds.length).equals(1); + + // Update the array element with condition == 1 to have status == true + let filter = { runId, name: "arrayFilter" }; + let update = {"$set": {"values.$[element].status": true}}; + let arrayFilters = [{"element.condition": 1 }]; + const result = await collection.updateOne(filter, update, { arrayFilters }); + // Check the result + expect(typeof result).equals("object"); + expect(result.matchedCount).equals(1); + expect(result.modifiedCount).equals(1); + + // Fetch the document to ensure that only the filtered elements of the array were updated + const doc = await collection.findOne({ runId, name: "arrayFilter" }); + if (doc === null) { + throw new Error("Expected a result"); + } else { + expect(doc.values.find(e => e.condition === 1).status).equals(true); + expect(doc.values.find(e => e.condition === 2).status).equals(false); + } + }); + it("upserts when updating many non-existing documents", async () => { const collection = getCollection(); // Delete the document with the last name (Charlie) diff --git a/packages/realm-web/src/services/MongoDBService/MongoDBCollection.ts b/packages/realm-web/src/services/MongoDBService/MongoDBCollection.ts index 87292ac87e7..1c274f9bb1b 100644 --- a/packages/realm-web/src/services/MongoDBService/MongoDBCollection.ts +++ b/packages/realm-web/src/services/MongoDBService/MongoDBCollection.ts @@ -215,6 +215,7 @@ export class MongoDBCollection implements Realm.Services.Mon query: filter, update, upsert: options.upsert, + arrayFilters: options.arrayFilters, }); } @@ -230,6 +231,7 @@ export class MongoDBCollection implements Realm.Services.Mon query: filter, update, upsert: options.upsert, + arrayFilters: options.arrayFilters, }); } diff --git a/types/services.d.ts b/types/services.d.ts index 26d13743065..d9bba6962c9 100644 --- a/types/services.d.ts +++ b/types/services.d.ts @@ -122,6 +122,10 @@ declare namespace Realm { * When true, creates a new document if no document matches the query. */ readonly upsert?: boolean; + /** + * Array Filters + */ + readonly arrayFilters?: Filter[] } /**