Trigger to automatically value the _partition field

Good evening everyone,

I ask for the help of the community because we are setting up a realm environment with partition sync and I would like to understand if it is possible to perform some operations automatically.

Our application foresees that a user can create documents in a collection called “sites” and that he can share these documents with other users.

as a partitioning system we have chosen to use a _partition field in the documents of the “sites” collection.

to share the “site” documents we have created two arrays in the custom data of each user: readPartitions and writePartitions which respectively contain the partitions that a user can read and read / write. For a user to be able to share a document with another user in read-only mode, he must launch a function that inserts the document partition in the readPartitions array of the user with whom he wants to share the document.

for each “site” document in the “sites” collection we used a string composed of the prefix “site_” and the objectId of the “site” document as the value of the _partition field. Eg:

{
    ...,
    _partition: "site_76e68a7587387e8f7678"
}

what we would like to create is a trigger that is triggered when a “site” document is created and which automatically values ​​the _partition field of the document just created and, at the same time, inserts the value of the partition in the writePartition array present in the custom data of the user who made the insertion.

it’s possible to do it?

thank you.

You could do this with a database trigger, though there are a few things to keep in mind

triggered when a “site” document is created and which automatically values ​​the _partition field of the document just created

To do this you would just construct the partition string for the site and update the document’s _partition field. You may run into some issues here if your schema and sync config have _partition as required.

inserts the value of the partition in the writePartition array present in the custom data of the user who made the insertion

Similarly this would just be an update operation in MongoDB that you write in your trigger function. However, you’d need to include the ID of the user that created the site in the document when you create it - DB triggers don’t inherently know which user inserted the document that caused a change event.

With the above considerations, your db trigger function would look something like this:

exports = async function ({ documentKey, fullDocument }) {
  const mdb = context.services.get("mongodb-atlas");
  const sites = mdb.db("app").collection("sites");
  const users = mdb.db("app").collection("users");

  const site_id = documentKey._id;
  const creator = fullDocument.creator;
  const sitePartition = `site_${site_id}`;

  // Set the site's partition key
  await sites.updateOne(
    { _id: site_id },
    { $set: { _partition: sitePartition } }
  );

  // Add the site to the creator's custom user data permissions
  await users.updateOne(
    { userId: creator },
    { $addToSet: { writePartition: sitePartition } }
  );
};

and if you’re concerned about errors or mismatched state between the queries, you can wrap everything in a transaction:

exports = async function ({ documentKey, fullDocument }) {
  const mdb = context.services.get("mongodb-atlas");
  const sites = mdb.db("app").collection("sites");
  const users = mdb.db("app").collection("users");

  const site_id = documentKey._id;
  const creator = fullDocument.creator;
  const sitePartition = `site_${site_id}`;

  const session = mdb.startSession();
  try {
    await session.withTransaction(async () => {
      // Set the site's partition key
      await sites.updateOne(
        { _id: site_id },
        { $set: { _partition: sitePartition } },
        { session }
      );
      // Add the site to the creator's custom user data permissions
      await users.updateOne(
        { userId: creator },
        { $addToSet: { writePartition: sitePartition } },
        { session }
      );
    });
  } catch (err) {
    await session.abortTransaction();
  } finally {
    await session.endSession();
  }
};

thank you @nlarew

i’ll try your solution as soon as possible.

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