简体   繁体   中英

How to do an atomic custom update of a mongodb document?

I am aware that MongoDB can do atomic updates using findOneAndModify but this only permits basic operations like set or increment.

What I need is to apply a custom function to transform my document:

const updateDoc = async (event) => {
  const oldState = await db.collection(collectionName).findOne({ name });
  const newState = customFunction(oldState, event);
  await db.collection(collectionName).replaceOne({ name }, newState);
}

This function will be called by a system that won't wait for a resolved promise to continue working: there can be multiple synchronous calls.

Is there a way to rewrite updateDoc to make it atomic, so that when we do:

updateDoc(event1); // note the absence of await
updateDoc(event2);

We can be sure that the stored doc will be customFunction(customFunction(initState, event1), event2) ?

Thanks

A possible solution would be a task queue, that shedules one update after another:

class Scheduler {
  constructor(){
    this.running = false;
    this.queue = [];
  }

  add(el){
     this.queue.push(el);
     if(!this.running) this.run();
  }

  async run(){
    this.running = true;
    while(this.queue.length) await this.queue.shift();
    this.running = false;
 }
}

Usable like this:

 const dbTasks = new Sheduler();

 const updateDoc = async (event) => dbTasks.add( _ => {
   const oldState = await db.collection(collectionName).findOne({ name });
   const newState = customFunction(oldState, event);
   await db.collection(collectionName).replaceOne({ name }, newState);
});

updateDoc(evt1);
updateDoc(evt2);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM