Update embedded document

Hi everyone, I’m a real newbie to the noSQL world and I wanted to play with it in combination with DDD. I have some doubts about updating data that is partially duplicated from one aggregate to another. Lets take an example:

I’m modelling an online personal lecture system with Teachers and Students. Students can enroll to the course proposed by a Teacher. The Enrollment is private between the Teacher and the Student. The Teacher can assign exercises to the Student through the Enrollment. The Student can submit the completed exercise. After the Enrollment period is done, the System remove the Enrollment.

In Mongo, I would model three main Documents: Teacher, Student and Enrollment. I Explicitly created an Enrollment Aggregate/Document, so that the Students and the Teachers can directly enquire all the active Enrollments.

The Mongo Documents:

Student {
    id,
    name,
    surname,
    birthDate,
    address
}

Teacher {
    id,
    name,
    surname,
    birthDate,
    address,
    courseInformation: {}
}

Enrollment {
  student: {
      name,
      surname,
      address
  },
  teacher: {
      name,
      surname
  },
  exercises: {...}
 }

Assume that for some reason the Enrollment is interested in keeping the address consistent with the Student address.
Mongo now has multi document ACID transactions, but I’m trying to follow DDD principles and make asynchronous updates across Aggregates/Documents.
My question is, prior multi document ACID transactions, how one can maintain consistency between data copied across multiple documents?
Was some sort of messaging mechanism used? I’m quite afraid of implementing a messaging system due to the difficulties of atomic and reliable aggregate update + message send.

Thank you

Hi @Green,

Welcome to MongoDB community .

Keeping atomic consistency across multiple documents is best achieved with transactions and there are many challenges of achieving it without it.

A good approach will be to try and reduce the places we need to update a value even in the price of referencing another document in a read.

For example why wouldn’t you hold the address on the student document and use a extended reference pattern to fetch the most up to date address from student collection pointing to its _id. Additionally, do you need to keep the address of the enrollment time or the most up to date one?

If you still need to keep the documents in sync you have several options:

  1. Use findAndUpdate commands to first query and update the documents with a flag that they are in mid change.
  2. Update both documents with the address
  3. Unflag the documents.

Another option is to use change streams available from 3.6 and to have a module listening for updates to addresses and update the enrollment documents.

Let me know if that helps.

Thanks
Pavel

1 Like

Hi @Pavel_Duchovny, thank you for your reply. As a premise, I’m just experimenting with DDD. I fully agree with your point about transactions, but I would like to follow the DDD principles by asynchronously updated aggregates and try to clearly separate the access to the domain model by the services. I would like to isolate as much as possible so that each service talks to only one aggregate.
On your point about the address, of course, the address is not probably going to change frequently, but I take this just as an example.
About, the extended reference, I would model it this way right?

Enrollment {
    student_id,
    student: {
        name,
        surname
    },
    teacher_id,
    teacher: {
        name,
        surname
    },
    exercises: {...}
}

Of course the name and surname are not going to change, so I dont have to worry about. For the address it means that when I access the Enrollment I need two queries correct? One for the enrollment and the second lookup for the address.

Regarding the change streams, I read about that, but this looks a lot like CQRS, which is something that frighten me a little bit :slight_smile:

Thank you!