fakemongo / fongo

faked out in-memory mongo for java
Apache License 2.0
523 stars 155 forks source link

Failed update embedded documents using $elemMatch #375

Open mincong-h opened 4 years ago

mincong-h commented 4 years ago

Overview

Given the following document in collection:

{
   "name" : "Tenant 1",
   "appAllocations" : [
     { "appId" : "68e1cf5a-0253-4c4a-9bc1-1eb3f27d0902" , "maxUser" : 4 },
     { "appId" : "1bb05dc0-3acf-41a3-a5c2-551db93187fb" , "maxUser" : 42 }
  ]
}

When filtering it via $elemMatch and updating the entire embedded via positional operator $, the update failed:

"$set" : {
  "appAllocations.$" : {
    "appId" : "68e1cf5a-0253-4c4a-9bc1-1eb3f27d0902",
    "maxUser" : 9
  }
}

Then the update failed:

org.junit.ComparisonFailure: 
Expected :{ "name" : "Tenant 1" , "appAllocations" : [ { "appId" : "68e1cf5a-0253-4c4a-9bc1-1eb3f27d0902" , "maxUser" : 9} , { "appId" : "1bb05dc0-3acf-41a3-a5c2-551db93187fb" , "maxUser" : 42}]}
Actual   :{ "name" : "Tenant 1" , "appAllocations" : [ { "appId" : "68e1cf5a-0253-4c4a-9bc1-1eb3f27d0902" , "maxUser" : 4} , { "appId" : "1bb05dc0-3acf-41a3-a5c2-551db93187fb" , "maxUser" : 42}]}

However, this works on real MongoDB.

Workaround

Only update one field:

"$set" : {  "appAllocations.$.maxUser" : 9 }

Reproduction

@Test
public void testPositionalOperatorWithElemMatch2() {
  String random1 = UUID.randomUUID().toString();
  String random2 = UUID.randomUUID().toString();

  DBObject object = (DBObject) FongoJSON.parse("{ \"name\" : \"Tenant 1\", \"appAllocations\" : [ { \"appId\" : \""
      + random1 + "\" , \"maxUser\" : 4} , { \"appId\""
      + ": \"" + random2 + "\" , \"maxUser\" : 42}]}");
  DBObject query = (DBObject) FongoJSON.parse("{ \"appAllocations\" : { \"$elemMatch\" : { \"appId\" : \"" + random1 + "\"}}}");
  DBObject update = (DBObject) FongoJSON.parse("{ \"$set\" : { \"appAllocations.$\" : { \"appId\" : \"" + random1 + "\", \"maxUser\" : 9 }}}");
  System.out.println("update: " + update);

  DBObject expected = (DBObject) FongoJSON.parse("{ \"name\" : \"Tenant 1\", \"appAllocations\" : [ { \"appId\" : \""
      + random1 + "\" , \"maxUser\" : 9} , { \"appId\""
      + ": \"" + random2 + "\" , \"maxUser\" : 42}]}");
  UpdateEngine updateEngine = new UpdateEngine();

  assertEquals(expected.toString(),
      updateEngine.doUpdate(object, update, query, false).toString());
}