Transaction inside realm function with sync enabled and partition strategy

Hello everyone,
I have a problem on my Atlas cluster with partition sync.

in a cloud function with realm authentication I need to create a partition (string), add the partition to the “writePartitions” array of the user’s custom data and, with the same operation, create an object that has the newly created partition.

I would like to put everything in a transaction to avoid that, if the insert fails, the user will end up with an “orphan” partition in his “writePartitions” list.

with the code I created, the function returns a 403 error as if the user did not have permission to insert an object with the specified partition but, theoretically, inserting the partition into the “writePartitions” array happens BEFORE inserting of the object.

I don’t understand where the problem is.


exports = async function(site){
  
  let user = context.user;
  
  const _id = new BSON.ObjectId();
  const _partition = "site_".concat(_id.toString());
  const userId = user.id;
  
  site._id = _id;
  site._partition = _partition;
  site.creationUserId = userId;
  
  const client  = context.services.get("mongodb-atlas");
  const session = client.startSession();

  // mettere il db name come value
  let profileCollection = client.db("accounts").collection("profile");
  let siteCollection = client.db("sias").collection("site");
  let result = {};
  
  const transactionOptions = {
    readPreference: 'primary',
    readConcern: { level: 'local' },
    writeConcern: { w: 'majority' }
  };
  
  try {
    await session.withTransaction(
      async () => {
        
        // Important:: You must pass the session to the operations
        await profileCollection.findOneAndUpdate({}, 
          { 
            $push: { "writePartitions": _partition }
          }, 
          { session }
        );
        
        result = await siteCollection.insertOne(site, { session });
        
      }, transactionOptions
    );
    
    
  } catch (e) {
    await session.abortTransaction();
    throw e;
  } finally {
   await session.endSession();
  }
 
  return result;
};

this is the error:

Error:

insert not permitted for document with _id: ObjectID(“62ab54ebf40def89cc22787f”)

finally i managed to get all this stuff working.

just for reference if someone else has the same problem:

exports = async function(site){
  
  let user = context.user;
  const userId = user.id;
  
  const client  = context.services.get("mongodb-atlas");
  const session = client.startSession();

  // mettere il db name come value
  let profileCollection = client.db("accounts").collection("profile");
  let siteCollection = client.db("sias").collection("site");
  
  site._partition = "user_".concat(user.id);
  site.creationDate = new Date();
  site.creationUserId = userId;

  const transactionOptions = {
    writeConcern: { w: 'majority' }
  };
  
  try {
    let result = {};
    await session.withTransaction(
      async () => {

        const insertResult = await siteCollection.insertOne(site, { session });
        
        const siteId = insertResult.insertedId;
        const _partition = "site_".concat(siteId);
        
        const updateResult1 = await profileCollection.updateOne({userId: userId},{ $push: { writePartitions : _partition }}, { session });
        const updateResult2 = await siteCollection.updateOne({_id: siteId}, [{ "$set": { _partition: _partition }}], { session });
        
        result = await siteCollection.findOne({_id: siteId});
        
      }, transactionOptions
    );
    return result;
    
  } catch (e) {
    await session.abortTransaction();
    throw e;
  } finally {
    await session.endSession();
  }

};

I hope this will help someone.

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.