1- import { MongoClient , ObjectID , Db , Binary , InsertOneWriteOpResult , MapReduceOptions , CollectionInsertOneOptions , GridFSBucket , ChangeStream , CollectionAggregationOptions , MongoClientOptions } from "mongodb" ;
1+ import { MongoClient , ObjectID , Db , Binary , InsertOneWriteOpResult , MapReduceOptions , CollectionInsertOneOptions , GridFSBucket , ChangeStream , CollectionAggregationOptions , MongoClientOptions , ReplaceOneOptions } from "mongodb" ;
22import { Crypt } from "./Crypt" ;
33import { Config } from "./Config" ;
44import { TokenUser , Base , WellknownIds , Rights , NoderedUtil , mapFunc , finalizeFunc , reduceFunc , Ace , UpdateOneMessage , UpdateManyMessage , InsertOrUpdateOneMessage , Role , Rolemember , User , Customer , WatchEventMessage } from "@openiap/openflow-api" ;
@@ -1518,7 +1518,9 @@ export class DatabaseConnection extends events.EventEmitter {
15181518 if ( NoderedUtil . IsNullEmpty ( name ) ) name = ( q . item as any ) . _name ;
15191519 if ( NoderedUtil . IsNullEmpty ( name ) ) name = "Unknown" ;
15201520 original = await this . getbyid < T > ( q . item . _id , q . collectionname , q . jwt , span ) ;
1521- if ( ! original ) { throw Error ( "item not found or Access Denied" ) ; }
1521+ if ( ! original ) {
1522+ throw Error ( "item not found or Access Denied" ) ;
1523+ }
15221524 if ( ! DatabaseConnection . hasAuthorization ( user , original , Rights . update ) ) {
15231525 throw new Error ( "Access denied, no authorization to UpdateOne " + q . item . _type + " " + name + " to database" ) ;
15241526 }
@@ -1744,7 +1746,10 @@ export class DatabaseConnection extends events.EventEmitter {
17441746 if ( q . query === null || q . query === undefined ) {
17451747 const id : string = q . item . _id ;
17461748 const safeid = safeObjectID ( id ) ;
1747- q . query = { $or : [ { _id : id } , { _id : safeObjectID ( id ) } ] } ;
1749+ q . query = { _id : id } ;
1750+ if ( safeid != null ) {
1751+ q . query = { $or : [ { _id : id } , { _id : safeid } ] } ;
1752+ }
17481753 }
17491754 let _query : Object = { } ;
17501755 if ( DatabaseConnection . usemetadata ( q . collectionname ) ) {
@@ -1753,11 +1758,12 @@ export class DatabaseConnection extends events.EventEmitter {
17531758 // todo: enforcer permissions when fetching _hist ?
17541759 _query = { $and : [ q . query , this . getbasequery ( q . jwt , "_acl" , [ Rights . update ] ) ] } ;
17551760 }
1761+ if ( Config . api_bypass_perm_check ) { _query = q . query ; }
17561762
17571763 q . j = ( ( q . j as any ) === 'true' || q . j === true ) ;
17581764 if ( ( q . w as any ) !== "majority" ) q . w = parseInt ( ( q . w as any ) ) ;
17591765
1760- let options : CollectionInsertOneOptions = { writeConcern : { w : q . w , j : q . j } } ;
1766+ let options : ReplaceOneOptions = { writeConcern : { w : q . w , j : q . j } , upsert : false } ;
17611767 ( options as any ) . WriteConcern = { w : q . w , j : q . j } ;
17621768 if ( NoderedUtil . IsNullEmpty ( this . replicat ) ) options = null ;
17631769
@@ -1788,18 +1794,34 @@ export class DatabaseConnection extends events.EventEmitter {
17881794 }
17891795 }
17901796 if ( ! DatabaseConnection . usemetadata ( q . collectionname ) ) {
1791- const ot_end = Logger . otel . startTimer ( ) ;
1792- const mongodbspan : Span = Logger . otel . startSubSpan ( "mongodb.replaceOne" , span ) ;
1793- q . opresult = await this . db . collection ( q . collectionname ) . replaceOne ( _query , q . item , options ) ;
1794- Logger . otel . endSpan ( mongodbspan ) ;
1795- Logger . otel . endTimer ( ot_end , DatabaseConnection . mongodb_replace , { collection : q . collectionname } ) ;
1797+ try {
1798+ const ot_end = Logger . otel . startTimer ( ) ;
1799+ const mongodbspan : Span = Logger . otel . startSubSpan ( "mongodb.replaceOne" , span ) ;
1800+ q . opresult = await this . db . collection ( q . collectionname ) . replaceOne ( _query , q . item , options ) ;
1801+ Logger . otel . endSpan ( mongodbspan ) ;
1802+ Logger . otel . endTimer ( ot_end , DatabaseConnection . mongodb_replace , { collection : q . collectionname } ) ;
1803+ } catch ( error ) {
1804+ var msg : string = error . message ;
1805+ if ( msg . startsWith ( "After applying the update, the (immutable) field '_id' was found" ) ) {
1806+ const safeid = safeObjectID ( q . item . _id ) ;
1807+ q . opresult = await this . db . collection ( q . collectionname ) . insertOne ( q . item ) ;
1808+ q . opresult . matchedCount = q . opresult . insertedCount ;
1809+ await this . db . collection ( q . collectionname ) . deleteOne ( { _id : safeid } ) ;
1810+ }
1811+ }
1812+ if ( q . opresult . matchedCount == 0 && ( q . w != 0 ) ) {
1813+ throw new Error ( "ReplaceOne failed, matched 0 documents with query {_id: '" + q . item . _id + "'}" ) ;
1814+ }
17961815 } else {
17971816 const fsc = Config . db . db . collection ( q . collectionname ) ;
17981817 const ot_end = Logger . otel . startTimer ( ) ;
17991818 const mongodbspan : Span = Logger . otel . startSubSpan ( "mongodb.replaceOne" , span ) ;
18001819 q . opresult = await fsc . updateOne ( _query , { $set : { metadata : ( q . item as any ) . metadata } } ) ;
18011820 Logger . otel . endSpan ( mongodbspan ) ;
18021821 Logger . otel . endTimer ( ot_end , DatabaseConnection . mongodb_update , { collection : q . collectionname } ) ;
1822+ if ( q . opresult . matchedCount == 0 && ( q . w != 0 ) ) {
1823+ throw new Error ( "ReplaceOne failed, matched 0 documents with query {_id: '" + q . item . _id + "'}" ) ;
1824+ }
18031825 }
18041826 } else {
18051827 if ( ( q . item [ "$set" ] ) === undefined ) { ( q . item [ "$set" ] ) = { } } ;
0 commit comments