javamongodbspring-mongo

Spring MongoDB Criteria update


How can I write the query to update the "contacts.collection.value._class = SubClass2" and set the value to xyz with Spring Mongodb Criteria?

{ "_class" : "MyClass",
  "_id" : ObjectId( "51ecc95503644e4489bb742e" ),
  "contacts" : [ 
    { "property1" : "Value1",
      "property2" : "Value2",
      "collection" : [ 
        { "value" : "1",
          "_class" : "SubClass1" }, 
        { "value" : "2",
          "_class" : "SubClass2" }, 
        { "value" : "2",
          "_class" : "SubClass3" }, 

I am trying to do this with Spring Data Mongo Criteria class.

So far I got this but it's not working

            query = new Query(Criteria.where("_id").is(myClassId)
                    .and("contacts.collection.value").is("2")
                    .and("contacts.collection._class").is("SubClass2"));
            update.set("contacts.collection.$.value", "3");
            mongoTemplate.updateFirst(query, update, MyClass.class);

I'm getting this error;

java.lang.IllegalArgumentException: No property value found on ...!

Notes:

  1. The "contacts" collection is a list of some interface.
  2. I sanitized the variable names and class names.
  3. If you don't know how to do it with Criteria, please give me the java code.

Thanks

Adding stacktrace

Here is the stack trace

java.lang.IllegalArgumentException: No property xyz found on com.blah.SomeInterface!
        at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentPropertyPath(AbstractMappingContext.java:225) ~[spring-data-commons-1.5.1.RELEASE.jar:na]
        at org.springframework.data.mongodb.core.convert.QueryMapper.getPath(QueryMapper.java:202) ~[spring-data-mongodb-1.2.1.RELEASE.jar:na]
        at org.springframework.data.mongodb.core.convert.QueryMapper.getTargetProperty(QueryMapper.java:190) ~[spring-data-mongodb-1.2.1.RELEASE.jar:na]
        at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedObject(QueryMapper.java:86) ~[spring-data-mongodb-1.2.1.RELEASE.jar:na]
        at org.springframework.data.mongodb.core.MongoTemplate$11.doInCollection(MongoTemplate.java:925) ~[spring-data-mongodb-1.2.1.RELEASE.jar:na]
        at org.springframework.data.mongodb.core.MongoTemplate$11.doInCollection(MongoTemplate.java:920) ~[spring-data-mongodb-1.2.1.RELEASE.jar:na]
        at org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:388) ~[spring-data-mongodb-1.2.1.RELEASE.jar:na]
        at org.springframework.data.mongodb.core.MongoTemplate.doUpdate(MongoTemplate.java:920) ~[spring-data-mongodb-1.2.1.RELEASE.jar:na]
        at org.springframework.data.mongodb.core.MongoTemplate.updateFirst(MongoTemplate.java:902) ~[spring-data-mongodb-1.2.1.RELEASE.jar:na]

Based on Jayz's answer, I wrote the update with RoboMongo and it works updates the query result!

db.myDB.update(
{
"_id":ObjectId("51ecc95503644e4489bb742e"),
"contacts.collection._class": "SubClass1",
"contacts.collection.value": "1",
},
{ 
    $set: { 'contacts.0.collection.$.value': '3' } 
},
{ getLastError: 1 });

But when I try to do it with mongoTemplate nothing is updated.


Solution

  • query will get you the index of the collection array which matches query criteria. With your data structure, you need two array indexes, one for contacts and one for collection, which is not possible (as far as I know). You need to know the position of either the contacts array item or the collection array item. Let's assume you know the position of the contacts array item. if it is 0th position, here is your complete query:

    query = new Query(new Criteria().andOperator(
            Criteria.where("_id").is(myClassId),
            Criteria.where("contacts.collection.value").is("2"),
            Criteria.where("contacts.collection._class").is("SubClass2"));
            update.set("contacts.0.collection.$.value", "3");
            mongoTemplate.updateFirst(query, update, MyClass.class);