5

I am running on Mongodb 3.6, with mongo driver 3.4.3 and spring data mongo 1.5.10. Below is the structure of my document

{
  "_id": 12345,
  "_class": "com.example.ProductRates",
  "rates": [
    {
      "productId": NumberInt(1234),
      "rate": 100.0,
      "rateCardId": NumberInt(1),
      "month": NumberInt(201801)
    },
    {
      "productId": NumberInt(1234),
      "rate": 200.0,
      "rateCardId": NumberInt(1),
      "month": NumberInt(201802)
    },
    {
      "productId": NumberInt(1234),
      "rate": 400.0,
      "rateCardId": NumberInt(2),
      "month": NumberInt(201803)
    },
    {
      "productId": NumberInt(1235),
      "rate": 500.0,
      "rateCardId": NumberInt(1),
      "month": NumberInt(201801)
    },
    {
      "productId": NumberInt(1235),
      "rate": 234,
      "rateCardId": NumberInt(2),
      "month": NumberInt(201803)
    }
  ]
}

am trying to do bulk update on the data as shown below

db.rates.update(
  { "_id" : 1234 },
  { $set: { "rates.$[item].rate": 200  } },
  { multi: true, 
   arrayFilters: [ { "item.rateCardId": {$in: [ 1, 2]} } ]
  }
)

Now and trying to convert this code to java. Below is the code i was able to achieve for a bulk update case. As expected the below query is updating all the document due to the usage of $[]. Am trying to figure out how to apply array filters here using positional array update operators (like $[one] ).

WriteResult wr = getMongoTemplate().updateMulti(
            new Query(where("rates.rateCardId").is(1234)),
            new Update().set("rates.$[].rate", 200),
            ProductRates.class);

Also I could not find enough tutorials or documentation that suggests how to apply all the complex mongo queries in Java. please suggest if there are any good books or tutorial i can refer to.

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
Kumaran
  • 125
  • 2
  • 6

2 Answers2

8

That should be:

WriteResult wr = getMongoTemplate().updateMulti(
  new Query(where("rates.rateCardId").is(1234)),
  new Update().set("rates.$[item].rate", 200),
  new UpdateOptions()
    .arrayFilters(
      Arrays.asList( Filters.in("item.rateCardId",Arrays.asList(1,2)) )
    ), 
  ProductRates.class
);

You need to make sure the underlying Java Driver is a 3.6.x version or greater in order to have the arrayFilters() and likely even to support the addition of UpdateOptions()

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
  • 1
    "Java Driver is a 3.6.x" - None of the Spring data 1.5.x versions support this. So is it mandatory to get upgraded to 2.x to use mongo 3.6 related features? – Kumaran Apr 19 '18 at 13:06
  • @Kumaran If you want MongoDB 3.6 features like `arrayFilters` then yes you **must** have a supporting driver. Spring Mongo versions prior to 2.x use deprecated interfaces that are marked for removal. Some quite possibly by the time MongoDB 4.x ships and driver updates are made again. See [Driver Compatibility](https://docs.mongodb.com/ecosystem/drivers/driver-compatibility-reference/) – Neil Lunn Apr 19 '18 at 13:12
2

I found Neil's answer useful in solving this problem, but I wanted to offer a slightly different call than the one in his code snippet.

getMongoTemplate().getCollection("ProductRates").updateMany(
    new Document().append("rates.rateCardId", 1234),
    new Document().append("$set", new Document().append("rates.$[item].rate", 200)),
    new UpdateOptions()
        .arrayFilters(
            Collections.singletonList( Filters.in("item.rateCardId",
                                                 Arrays.asList(1,2)) ))
);
zagger
  • 21
  • 2
  • I have a question. Is there a way to work with Objects? You just append Text but I need something like a BasicDBObject. I find your answer much better. Got a like! – ru4ert Jun 11 '20 at 16:02