code: public static Set<Event> compareAndGetEvents(JSONObject pre, JSONObject post, JSONObject ids) throws JSONException {
          Set<Event> result = new HashSet<>();
          Iterator<String> keysIterator = ids.keys();
          while (keysIterator.hasNext()) {
              String key = keysIterator.next();
              if (post.get(key) instanceof JSONObject || post.get(key) instanceof JSONArray) {
                  Object preObject = (pre == null) ? null : pre.opt(key);
                  Set<Event> events = compareAndGetEvents(preObject, post.get(key), ids.get(key));
                  for (Event event : events) {
                      for (Identity identity : event.getIdentity()) {
                          identity.setField(key + "." + identity.getField());
                      }
                  }
                  result = crossMultiplySets(result, events);
              } else {
                  Identity i = new Identity();
                  i.setField(key);
                  i.setValue(post.get(key).toString());
                  Operation operation = (pre == null) ? Operation.INSERT : Operation.UPDATE;
                  if (result.size() == 0) {
                      Event event = new Event();
                      event.setOperation(operation);
                      result.add(event);
                  }
                  for (Event event : result) {
                      event.getIdentity().add(i);
                  }
              }
          }
          return result;
      }
docs: /*
  For child objects and child arrays, cross multiply the number of simple
  fields. This is because we need one event per child array element that
  changed.