user5778069
user5778069

Reputation:

How to update document in mongo to get performance?

I am new to Spring Data Mongo. I've a scenario where I want to create a Study if already not present in mongo db. If its already present, then I've to update it with the new values.

I tried in the following way, which works fine in my case, but I'm not sure this is the correct/Best/Advisable way to update etc as far as performance is concerned.

Could anyone please guide on this?

public void saveStudy(List<Study> studies) {
        for (Study study : studies) {
            String id = study.getId();
            Study presentInDBStudy = studyRepository.findOne(id);

            //find the document, modify and update it with save() method.
            if(presentInDBStudy != null) {
                presentInDBStudy.setTitle(task.getTitle());
                presentInDBStudy.setDescription(study.getDescription());    
                presentInDBStudy.setStart(study.getStart());
                presentInDBStudy.setEnd(study.getEnd());
                repository.save(presentInDBStudy);
            }
            else
                repository.save(study);
        }
    }

Upvotes: 5

Views: 953

Answers (3)

s7vr
s7vr

Reputation: 75934

You can update your code to use <S extends T> List<S> save(Iterable<S> entites); to save all the entities. Spring's MongoRepository will take care of all possible cases based on the presence of _id field and its value.

More information here https://docs.mongodb.com/manual/reference/method/db.collection.save/

This will work just fine for basic save operations. You don't have to load the document for update. Just set the id and make sure to include all the fields for update as it updates by replacing the existing document.

Simplified Domain Object:

@Document(collection = "study")
public class Study {
    @Id
    private String id;
    private String name;
    private String value;
}

Repository:

public interface StudyRepository extends MongoRepository<Study, String> {}

Imagine you've existing record with _id = 1

Collection state before:

{
        "_id" : 1,
        "_class" : "com.mongo.Study",
        "name" : "saveType",
        "value" : "insert"
}

Run all the possible cases:

public void saveStudies() {
        List<Study> studies = new ArrayList<Study>();

        --Updates the existing record by replacing with the below values.
        Study update = new Study();
        update.setId(1);
        update.setName("saveType");
        update.setValue("update");

        studies.add(update);

        --Inserts a new record.
        Study insert = new Study();
        insert.setName("saveType");
        insert.setValue("insert");

        studies.add(insert);

        --Upserts a record.
        Study upsert = new Study();
        upsert.setId(2);
        upsert.setName("saveType");
        upsert.setValue("upsert");

        studies.add(upsert);

        studyRepository.save(studies);

    }

Collection state after:

{
        "_id" : 1,
        "_class" : "com.mongo.Study",
        "name" : "saveType",
        "value" : "update"
}
{
        "_id" : 3,
        "_class" : "com.mongo.Study",
        "name" : "saveType",
        "value" : "insert"
}
{
        "_id" : 2,
        "_class" : "com.mongo.Study",
        "name" : "saveType",
        "value" : "upsert"
}

Upvotes: 1

Kihats
Kihats

Reputation: 3520

You will have to use the MongoTemplate.upsert() to achieve this. You will need to add two more classes: StudyRepositoryCustom which is an interface and a class that extends this interface, say StudyRepositoryImpl

interface StudyRepositoryCustom {
   public WriteResult updateStudy(Study study);
}

Update your current StudyRepository to extend this interface

@Repository
public interface StudyRepository extends MongoRepository<Study, String>, StudyRepositoryCustom {
   // ... Your code as before
}

And add a class that implements the StudyRepositoryCustom. This is where we will @Autowire our MongoTemplate and provide the implementation for updating a Study or saving it if it does not exist. We use the MongoTemplate.upsert() method.

class StudyRepositoryImpl implements StudyRepositoryCustom {
   @Autowired
   MongoTemplate mongoTemplate;

   public WriteResult updateStudy(Study study) {
      Query searchQuery = new Query(Criteria.where("id").is(study.getId());
      WriteResult update = mongoTemplate.upsert(searchQuery, Update.update("title", study.getTitle).set("description", study.getDescription()).set(...)), Study.class);
      return update;
   }
}

Kindly note that StudyRepositoryImpl will automatically be picked up by the Spring Data infrastructure as we've followed the naming convention of extending the core repository interface's name with Impl

Check this example on github, for @Autowire-ing a MongoTemplate and using custom repository as above.

I have not tested the code but it will guide you :-)

Upvotes: 2

KayV
KayV

Reputation: 13835

You can use upsert functionality for this as described in mongo documentation. https://docs.mongodb.com/v3.2/reference/method/db.collection.update/

Upvotes: 1

Related Questions