I have a list of embedded entities:
@Embedded
private List<EmbeddedEntity> embedded = new ArrayList<EmbeddedEntity>();
In this list, I want to search for any embedded entity which has a specific attribute (let’s call it foo), but not another one (bar). So foo should be non-null and bar null in Java / inexistant in MongoDB.
I tried the following code (I do have the UUID of the Entity containing the list):
Query<Entity> query = mongoDataStore.find(Entity.class).field("uuid").equal(uuid)
.field("embedded.foo").exists()
.field("embedded.bar").doesNotExist();
This works correctly if the list is empty or has a single entry (where foo has a value and bar does not yet exist). But as soon as any bar attribute has a value, the query returns the wrong result. So I’m looking for a query, which iterates through all the embedded entities and fires on any missing bar. Is that possible?
Example data:
// the query does not pick up the entity as it doesn't have a foo -
// that's what I want
{ uuid: "...", [ { embedded: } ] }
// the query picks up the entity as there is a foo but no bar -
// that's what I want
{ uuid: "...", [ { embedded: { foo: date } } ] }
// the query does not pick up the entity - that's not what I want
// as one foo has a value and its bar doesn't
{ uuid: "...", [ { embedded: { foo: date, bar: date } },
{ embedded: { foo: date } }
] }
PS: I get the same result with .field("embedded.bar").hasThisOne(null).
PPS: Manually iterating through the list elements is not really an option, as I want to use the query for an update operation.
PPS: I think this is a bug in Morphia – see my answer below (https://stackoverflow.com/a/9705175/573153) for a workaround
I’ve found a workaround. While I don’t seem to be able to query on null, I can query for a specific value.
In my case, the
barfield is a Date. So I can initialize the entity withprivate Date bar = new Date(0)– this is clearly an invalid date in my case, which is never used. So the query then looks like this:And in case anyone needs it, here is the update operation (you need to disable the validation as
.$.will otherwise raise an error):