Morphia MongoDB check for null and non existing field - mongodb

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?

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;
}
}

When you first create your Morphia instance, before calling morphia.mapPackage() do this:
morphia.getMapper().getOptions().setStoreNulls(true);
to have Morphia store null values.
Anyway, you should be able to query non-null values with:
query.field("createdDate").notEqual(null);

In mongo you can use this query:
db.MyCollection.find({"myField" : {$ne : null}})
This query will return objects that have the field 'myField' and has a value that is not null.

Related

MongoDB Complex Query with Java

We have following structure in MongoDB documents.
{
"id":"1111",
"keys":[
{
"name":"Country",
"value":"USA"
},
{
"name":"City",
"value":"LongIsland"
},
{
"name":"State",
"value":"NewYork"
}
]
}
Now using Springframework Query object, I figured out a way to pull the details using below syntax
query.addCriteria(
Criteria.where("keys.value").is(countryparam).
andOperator(
Criteria.where("keys.value").is(stateparam)
)
);
Two issue with this query model.
First issue is it is irrelevant if countryparam and stateparam are actually meant to match Country key name and State key name respectively. If just the values matches, the query returns the document. Means, if I have Country and City params, this just works if user passes Country and City values, even if they are swapped. So how can I exactly compare City to cityparam and State to Stateparam?
More complexity is if I have to extract the document basing on multiple key value pairs, I should be correspondingly able to match key name with respective value and query the document. How can I do this?
Thanks in advance!

Update Value in Mongo 3.6.0 while updating value inside json object

I want to update FieldA in someFields while someFields is null in MongoDB
{
"someFileds : {
"FieldA" : "ABS"
}
}
someFields may have more fields as well but Just want to ensure that other fields won't be overridden.
Sometime SomeFields won't be having any fields so want to
I am using below code for set the the value however value for someFields is null in MongoDB.
BasicDBObject dbObject = new BasicDBObject();
dbObject.put("SomeFields.FieldA", "TEST");
Could you please suggest how can handle the null in this scenario.
Use this Mongo update query.
db.collection.update({}, {$set:{"someFields": {"FieldA": "Test"}}});
It will create FieldA in someFields when it is null otherwise will only update FieldA.
In your case kindly pass object all time in 2nd parameter of put.
dbObject.put("SomeFields", {FieldA:"TEST"});

SortBy Spring Data MongoDb

I have passed my query from postgres to mongodb, everything is correct. But in the ordering I do not see how to integrate it within #Query as in the example sql
// sql-postgres ( repository )
#Query("select c from ClienteElser c where c.securityDomainId IN (2,10) and c.deleted is null order by c.razonSocial")
//mongodb ( repository )
#Query("{security_domain_id: { $in: [2,10] },'deleted':null}")
public List<Cliente> findAllByOrderByRazonSocialAsc(Sort sort);
//service
Sort sort = new Sort(Sort.Direction.ASC, "razon_social");
List<Cliente> result = clienteRepository.findAllByOrderByRazonSocialAsc(sort);
At the moment I have fixed it like that, but I would prefer it to be inside #Query
And order giving priority to capital letters, I do not know how to avoid that. Example : "ACS" is before "Abalos"
Can someone help me to integrate the sort within #Query with mongodb and that does not differ between uppercase and lowercase
Thank you
This has been adressed in DATAMONGO-1979 for the Lovelace release (aka Spring Data MongoDB 2.1.0).
It will allow to set a default sort for repository query methods via the #Query annotation.
#Query(sort = "{ age : -1 }")
List<Person> findByFirstname(String firstname);
Using an explicit Sort parameter along with the annotated one allows to alter the defaults set via the annotation. The method argument Sort parameters will be added to / or override the annotated defaults depending on the fields used.
#Query(sort = "{ age : -1 }")
List<Person> findByFirstname(String firstname, Sort sort);

Mongo's Time-To-Live (TTL) index does not work for me

MongoDb 2.0.7.
That is how date is declared for stored object MyObject in c#:
public class MyObject
{
[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
public DateTime Created { get; set; }
...
}
That is how index is created:
Collection.EnsureIndex(new IndexKeysBuilder<MyObject>().Ascending(l => l.Created), IndexOptions.SetName("CreatedDateIndex").SetTimeToLive(new TimeSpan(0, 0, 60)));
MongoVUE tool confirms that index named CreatedDateIndex is created for collection MyObject with expireAfterSeconds = 60. There no more indexes declared for the Created field.
However items in the collection are never auto-removed, I can see several days old items still here like this document:
{
"_id" : new BinData(3, "OVdRaIodPUKz7cCuaxnFpA=="),
"Created" : ISODate("2014-01-09T23:41:08.732Z"),
}
What might be wrong? I can only guess that something wrong is type of data, may be it's not of Bson Date type and it even does not warn me, anyway I do not even know how can I verify it.
TTL indexes are new since 2.2, while you are using 2.0.7 ...

MongoDB C# offic. List<BsonObject> query issue and always olds values?

I have not clearly issue during query using two criterials like Id and Other. I use a Repository storing some data like id,iso,value. I have created an index("_id","Iso") to performs queries but queries are only returning my cursor if i use only one criterial like _id, but is returning nothing if a use two (_id, Iso) (commented code).
Are the index affecting the response or the query method are failing?
use :v1.6.5 and C# official.
Sample.
//Getting Data
public List<BsonObject> Get_object(string ID, string Iso)
{
using (var helper = BsonHelper.Create())
{
//helper.Db.Repository.EnsureIndex("_Id","Iso");
var query = Query.EQ("_Id", ID);
//if (!String.IsNullOrEmpty(Iso))
// query = Query.And(query, Query.EQ("Iso", Iso));
var cursor = helper.Db.Repository.FindAs<BsonObject>(query);
return cursor.ToList();
}
}
Data:
{
"_id": "2345019",
"Iso": "UK",
"Data": "Some data"
}
After that I have Updated my data using Update.Set() methods. I can see the changed data using MongoView. The new data are correct but the query is always returning the sames olds values. To see these values i use a page that can eventually cached, but if add a timestamp at end are not changing anything, page is always returning the same olds data. Your comments are welcome, thanks.
I do not recall offhand how the C# driver creates indexes, but the shell command for creating an index is like this:
db.things.ensureIndex({j:1});
Notice the '1' which is like saying 'true'.
In your code, you have:
helper.Db.Repository.EnsureIndex("_Id","Iso");
Perhaps it should be:
helper.Db.Repository.EnsureIndex("_Id", 1);
helper.Db.Repository.EnsureIndex("Iso", 1);
It could also be related to the fact that you are creating indexes on "_Id" and the actual id field is called "_id" ... MongoDB is case sensitive.
Have a quick look through the index documentation: http://www.mongodb.org/display/DOCS/Indexes