首页 > 解决方案 > 在 MongoDB 中保持并发读取操作的一致性

问题描述

我在 Node.js 中有一个 API,说它/create/appointment执行 2 个操作

第 1 步:检查数据库中的活动约会。

第 2 步:如果不存在,则创建一个约会。

我有 3 个收藏

  1. doctors
  2. patients
  3. appointments

约会集合有 3 个主要领域

doctor_id:MongoDb ObjectID patient_id:MongoDB ObjectID is_active:布尔值

STEP 1 包含一个 DB 读取操作。STEP 2 包含一个 DB 写操作。当 API 同时触发多次时,第二个循环的 STEP 1 在第一个循环的 STEP 2 完成之前执行。由于第一个周期的 STEP 2 没有完成,所以第二个周期的 STEP 1 不会返回在第一个周期中创建的活动约会条目。

我不能在以下位置使用复合唯一索引:

  1. {doctor_id, patient_id},因为appointment集合可以包含历史数据。

  2. {doctor_id, patient_id, is_active},则appointment集合只能包含一个非活动条目。

执行:

// All functions below return promise object.
doctorManager
.getDoctor(doctor_id)
.then(doctor => {
  // throw error if doctor does not exist
  return patientManager.getPatient(patient_id);
})
.then(patient => {
  // throw error if patient does not exist
  return getActiveAppointment(doctor_id, patient_id)
})
.then(activeAppointment => {
  // throw error if active appointment exist
  return appointmentManager.createAppointment(doctor_id, patient_id)  
})
.then(() => {
  // return API response
})
.catch(error => {
  // handel error
});

有没有办法appointment在进行任何类型的操作时锁定集合,或者任何其他更好的解决方案。我不能对我的数据库进行分片,也不能设置复制。

标签: node.jsmongodbexpressmongoosemongodb-query

解决方案


这是使用异步等待功能时的外观。它不是问题解决方案,而只是正确处理问题的示例。

  doctor = await doctorManager.getDoctor(doctor_id);
  patient =  await patientManager.getPatient(patient_id);
  appointment  = await doAppointmentExists(doctor_id, patient_id);

  if(isEmpty(appointment)) {
     create appointment = await appointmentManager.createAppointment(doctor_id, patient_id)
  } else {
    throw new Error("Duplicate Appointment");
  }  

推荐阅读