Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java driver: how to get the objectId of an updated object with Mongodb's updateFirst method

Tags:

java

mongodb

I'm trying to get the objectId of an object that I have updated - this is my java code using the java driver:

    Query query = new Query();
    query.addCriteria(Criteria.where("color").is("pink"));
    Update update = new Update();
    update.set("name", name);
    WriteResult writeResult = mongoTemplate.updateFirst(query, update, Colors.class);

    Log.e("object id", writeResult.getUpsertedId().toString());

The log message returns null. I'm using a mongo server 3.0 on mongolab as I'm on the free tier so it shouldn't return null. My mongo shell is also:

MongoDB shell version: 3.0.7

Is there an easy way to return the object ID for the doc that I have just updated? What is the point of the method getUpsertedId() if I cannot return the upsertedId?

To do what I want, I currently have to issue two queries which is highly cumbersome:

    //1st query - updating the object first
    Query query = new Query();
    query.addCriteria(Criteria.where("color").is("pink"));
    Update update = new Update();
    update.set("name", name);
    WriteResult writeResult = mongoTemplate.updateFirst(query, update, Colors.class);
    //2nd query - find the object so that I can get its objectid
    Query queryColor = new Query();
    queryColor.addCriteria(Criteria.where("color").is("pink"));
    queryColor.addCriteria(Criteria.where("name").is(name));
    Color color = mongoTemplate.findOne(queryColor, Color.class);
    Log.e("ColorId", color.getId());

As per David's answer, I even tried his suggestion to rather use upsert on the template, so I changed the code to the below and it still does not work:

    Query query = new Query();
    query.addCriteria(Criteria.where("color").is("pink"));
    Update update = new Update();
    update.set("name", name);
    WriteResult writeResult = mongoTemplate.upsert(query, update, Colors.class);

    Log.e("object id", writeResult.getUpsertedId().toString());
like image 450
Simon Avatar asked Nov 14 '15 19:11

Simon


2 Answers

Simon, I think its possible to achieve in one query. What you need is a different method called findAndModify().

In java driver for mongoDB, it has a method called findOneAndUpdate(filter, update, options).

This method returns the document that was updated. Depending on the options you specified for the method, this will either be the document as it was before the update or as it is after the update. If no documents matched the query filter, then null will be returned. Its not required to pass options, in that case it will return the document that was updated before update operation was applied.

A quick look at the mongoTemplate java driver docs here: http://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb/core/FindAndModifyOptions.html tells me that you can use the method call:

public <T> T findAndModify(Query query,
                           Update update,
                           FindAndModifyOptions options,
                           Class<T> entityClass)

You can also change the FindAndModifyOptions class to take on an 'upsert' if the item was not found in the query.If it is found, the object will just be modified.

like image 109
Sarath Nair Avatar answered Sep 27 '22 16:09

Sarath Nair


Upsert only applies if both

  1. The update options had upsert on
  2. A new document was actually created.

Your query neither has upsert enabled, nor creates a new document. Therefore it makes perfect sense that the getUpsertedId() returns null here.

Unfortunately it is not possible to get what you want in a single call with the current API; you need to split it into two calls. This is further indicated by the Mongo shell API for WriteResults:

The _id of the document inserted by an upsert. Returned only if an upsert results in an insert.

like image 21
David says Reinstate Monica Avatar answered Sep 27 '22 17:09

David says Reinstate Monica