Search code examples
mongodbmorphia

Morphia MongoDB check for null and non existing field


I am new to both Morphia and MongoDB. Is there a way to check using Morphia that a certain field in my database is not null and also exists. For example from the following record of a user from a collection of users in database:

{ "_id" : ObjectId("51398e6e30044a944cc23e2e"), 
  "age" : 21 , 
  "createdDate" : ISODate("2013-03-08T07:08:30.168Z"),
  "name" : "Some name" }

How would I use a Morphia query to check if field "createdDate" is not null and exists.

EDIT: I am looking for a solution in Morphia. So far I have come up with this:

query.and(query.criteria("createdDate").exists(),
query.criteria("createdDate").notEqual(null));

From documentation, I learnt Morphia does not store empty or null fields. Hence the justification for notEqual(null).

EDIT 2: From the answers I can see the problem needs more explanation. I cannot modify the createdDate. To elaborate: the example above is less complex than my actual problem. My real problem has sensitive fields which I cannot modify. Also to complicate things a bit more, I do not have control over the model otherwise I could have used @PrePersist as proposed in one of the answers.

Is there a way to check for null and non existing field when I have no control over the model and I am not allowed to modify fields?


Solution

  • From the documentation, Morphia does not store Null/Empty values (by default) so the query

    query.and(
        query.criteria("createdDate").exists(),
        query.criteria("createdDate").notEqual(null)
    );
    

    will not work since it seems you are not able to query on null, but can query for a specific value.

    However, since you can only query for a specific value, you can devise a workaround where you can update the createdDate field with a date value that is never used in your model. For example, if you initialize a Date object with 0, it will be set to the beginning of the epoch, Jan 1st 1970 00:00:00 UTC. The hours you get is the localized time offset. It will be sufficient if your update only involves modifying the matching element(s) in mongo shell, hence it would look similarly to this:

    db.users.update(
        {"createdDate": null }, 
        { "$set": {"createdDate": new Date(0)} }
    )
    

    You can then use the Fluent Interface to query on that specific value:

    Query<User> query = mongoDataStore
        .find(User.class)    
        .field("createdDate").exists()
        .field("createdDate").hasThisOne(new Date(0));
    

    It would be much simpler when defining your model to include a prePersist method that updates the createdDate field. The method is tagged with the @PrePersist annotation so that the date is set on the order prior to it being saved. Equivalent annotations exist for @PostPersist, @PreLoad and @PostLoad.

    @Entity(value="users", noClassNameStored = true)
    public class User {
    
        // Properties
        private Date createdDate;
    
        ...
        // Getters and setters
        ..
    
        @PrePersist
        public void prePersist() {
            this.createdDate = (createdDate == null) ? new Date() : createdDate;
        }
    }