Skip to content

Commit

Permalink
Merge pull request #51 from lowdefy/mongo-update-insert
Browse files Browse the repository at this point in the history
MongoDBVersionedUpdateOne Request
  • Loading branch information
SamTolmay authored Nov 20, 2024
2 parents b128505 + cf6d0e0 commit 1297fda
Show file tree
Hide file tree
Showing 6 changed files with 898 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/hip-seas-camp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@lowdefy/community-plugin-mongodb': minor
---

Added MongoDBVersionedUpdateOne request.
76 changes: 76 additions & 0 deletions apps/docs/community-plugin-mongodb/MongoDB.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ _ref:
- MongoDBUpdateOne
- MongoDBInsertConsecutiveId
- MongoDBInsertManyConsecutiveIds
- MongoDBVersionedUpdateOne
### MongoDBUpdateOne
Expand Down Expand Up @@ -200,3 +201,78 @@ _ref:
...,
}
```
### MongoDBVersionedUpdateOne
#### Properties
The `MongoDBVersionedUpdateOne` request uses the standard [MongoDBUpdateOne](https://docs.lowdefy.com/MongoDB) syntax to insert an identical document to the one found with only the updated field(s) changed.
The `MongoDBVersionedUpdateOne` request consists of __three stages__:
- `Find`: locates the document.
- `Insert`: creates and inserts the document identical to the one found.
- `Update`: applies the specified changes to the inserted document.
The `options` property:
- `find: object` - An object containing options for the `find` stage of the request.
- `insert: object` - An object containing options for the `insert` stage of the request.
- `update: object` - An object containing options for the `update` stage of the request.
The request returns the following:
If a log collection is not set on the connection
- `acknowledged: boolean` - Acknowledgement of the insertion.
- `matchedCount: number` - The number of matched documents.
- `modifiedCount: number` - The number of modified documents.
- `upsertedId: string` - The ID of the upserted document.
- `upsertedCount: number` - The number of upserts.
If a log collection is set on the connection
- `lastErrorObject: object` - An object containing data on whether an existing document was updated or not.
- `ok: number` - Status of the request, 1 if the request was successful and 0 otherwise.
- `'$clusterTime': object` - An object containing data on the cluster time and signature.
- `operationTime: date` - Timestamp object of the operation time.
> To ensure that the most recent document is updated, a `sort` specification should be given in the find options.
#### Example
###### Find the document with the highest item number and insert an identical document with a new name. A new document is inserted if none is found.
```yaml
id: versioned_update
type: MongoDBVersionedUpdateOne
connectionId: items
properties:
filter:
entity_id: 123
update:
$set:
name: New Name
updated_at:
_date: now
options:
find:
sort:
updated_at: -1
update:
upsert: true
```
###### Before
```json
[
{"_id": ObjectId("..."), "entity_id": 123, "name": "Name", "value": 23,"updated_at": ISODate("2024-01-01") },
{"_id": ObjectId("..."), "entity_id": 123, "name": "Name", "value": 33, "updated_at": ISODate("2024-03-01")},
]
```
###### After
```json
[
{"_id": ObjectId("..."), "entity_id": 123, "name": "Name", "value": 23,"updated_at": ISODate("2024-01-01") },
{"_id": ObjectId("..."), "entity_id": 123, "name": "Name", "value": 33, "updated_at": ISODate("2024-03-01")},
{"_id": ObjectId("..."), "entity_id": 123, "name": "New Name", "value": 33, "updated_at": ISODate("2024-11-01")},
]
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
Copyright 2020-2023 Lowdefy, Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import getCollection from '../getCollection.js';
import { serialize, deserialize } from '../serialize.js';
import schema from './schema.js';

async function MongoDBVersionedUpdateOne({
blockId,
connection,
connectionId,
pageId,
request,
requestId,
payload,
}) {
const deserializedRequest = deserialize(request);
const { filter, update, options, disableNoMatchError } = deserializedRequest;
const { collection, client, logCollection } = await getCollection({ connection });
const findOptions = options?.find;
const insertOptions = options?.insert;
const updateOptions = options?.update;
let response, insertedDocument;

try {
const document = await collection.findOne(filter, { ...findOptions });
if (logCollection) {
if (document) {
delete document._id;
insertedDocument = await collection.insertOne(document, { ...insertOptions });
}

const { value, ...responseWithoutValue } = await collection.findOneAndUpdate(
insertedDocument ? { _id: insertedDocument.insertedId } : filter,
update,
{
...updateOptions,
includeResultMetadata: true,
returnDocument: 'after',
}
);
response = responseWithoutValue;
await logCollection.insertOne({
args: { filter, update, options },
blockId,
connectionId,
pageId,
payload,
requestId,
before: document,
after: value,
timestamp: new Date(),
type: 'MongoDBVersionedUpdateOne',
meta: connection.changeLog?.meta,
});
if (
!disableNoMatchError &&
!updateOptions?.upsert &&
!response.lastErrorObject.updatedExisting
) {
throw new Error('No matching record to update.');
}
} else {
if (document) {
delete document._id;
insertedDocument = await collection.insertOne(document, { ...insertOptions });
}

response = await collection.updateOne(
insertedDocument ? { _id: insertedDocument.insertedId } : filter,
update,
{ ...updateOptions }
);
if (!disableNoMatchError && !updateOptions?.upsert && response.matchedCount === 0) {
throw new Error('No matching record to update.');
}
}
} catch (error) {
await client.close();
throw error;
}
await client.close();
return serialize(response);
}

MongoDBVersionedUpdateOne.schema = schema;
MongoDBVersionedUpdateOne.meta = {
checkRead: false,
checkWrite: true,
};

export default MongoDBVersionedUpdateOne;
Loading

0 comments on commit 1297fda

Please sign in to comment.