MongoDB extracting values from BasicDBObject (Java) - java

I am having trouble retrieving values from queried documents in MongoDB.
For example, the doc structure is like:
{
"_id": {
"$oid": "50f93b74f9eccc540b302462"
},
"response": {
"result": {
"code": "1000",
"msg": "Command completed successfully"
},
"resData": {
"domain:infData": {
"domain:name": "ritesh.com",
"domain:crDate": "2007-06-15T12:02:36.0000Z",
"domain:exDate": "2013-06-15T12:02:36.0000Z"
}
}
}
}
And the query code is:
DBCollection collection = db.getCollection("domains");
BasicDBObject p = new BasicDBObject("response.resData.domain:infData.domain:name", "ritesh.com");
DBCursor c = collection.find(p);
while(c.hasNext()) {
DBObject obj = c.next();
Object value = obj.get("response.resData.domain:infData.domain:name");
}
It queries fine and fetches the doc, but I can't seem to figure out how to extract the value of "response.resData.domain:infData.domain:name" or other similarly nested values from the DBObject (or BasicDBObject since c.next() returns type BasicDBObject).
I could fetch the objects one at a time like:
((DBObject)obj.get("response")).get("resData")....
but that seems very cumbersome.
I thought since you can put() a nested field value in BasicDBObject like:
basicDBObject.put("response.resData.domain:infData.domain:name", "ritesh.com");
that I could similarly use get() to fetch from the BasicDBObject result using the same kind of key. Like I attempted to do in the code above with:
Object value = obj.get("response.resData.domain:infData.domain:name");
But that is returning a null value.
It's probably something straightforward, but I can't seem to figure it out. And everywhere I've checked on the net the examples only fetch values that aren't nested, from the result. Like
doc.get("name");
instead of something like:
doc.get("name.lastname.clanname");
Any help would be appreciated. Thanks!

There's no way to chain a property name like you're doing using the Java driver (gets for sure, and according to the this, put isn't supposed to work either).
You'll need to get the objects one at a time like you suggested.
((DBObject)obj.get("response")).get("resData")
See here for a potential future feature that would allow your syntax to possibly work (although, likely with a new method name).

I ran into the same problem and I wrote a small function to fetch chained properties.
private Object getFieldFromCursor(DBObject o, String fieldName) {
final String[] fieldParts = StringUtils.split(fieldName, '.');
int i = 1;
Object val = o.get(fieldParts[0]);
while(i < fieldParts.length && val instanceof DBObject) {
val = ((DBObject)val).get(fieldParts[i]);
i++;
}
return val;
}
I hope it helps.

Related

MongoDB updating an array element in a specific index using the Java driver

Usually, I avoid asking a new question as I always find a "close-enough" answer to my problem.
But this time I surprisingly have a fundamental and straightforward question - without any lead.
I have a straightforward MongoDB document that holds two arrays:
The 1st containing three numbers (ints) - each represent a code-number of a selected (predefined) question.
The 2nd was holding 3 Strings - that are the answers given by the user to these three correspondent questions.
For example, let's say subject code 12 is - "What's your 1st dog's name?", and the user's answer was: "Spiky", etc...
So I end up with something like:
{
"_id" : ObjectId("..."),
"questionCodesArray" : [
12,
56,
3
],
"answersArray" : [
"Spiky",
"go swimming",
"blabla.."
]
}
Now, I'd like to be able to allow the users to change their mind and choose a different question and supply a different answer to it.
For this, I need to have only the index of my element and access it via this index to change it using update() or findAndModify() [or any other method] and all the answers out there are "key-value style" which is not needed.
In simple Java I would've simply done something like:
questionsCodesArry[index] = newValue; and
answersArray[index] = newAnswerString;
All my attempts to write a descent query to do this simple index-based updating have failed.
Any help will be appreciated.
Thank you.
In plain MongoDB syntax what you need is this:
collection.update({
/*your filter goes here*/
}, {
$set: {
"questionCodesArray.<zero-based-index>": "new value"
}
})
I don't have a Java environment here to translate this into your driver's world. I might be able to do so tonight, though.
Still, I would definitely vote for a different, more natural and less error-prone design where you'd structure your data like so:
{
"_id" : ObjectId("59b635ffad44fad6662d8591"),
"answers" : [
{
"questionCode" : 12,
"answer" : "Spiky"
},
{
"questionCode" : 56,
"answer" : "go swimming"
},
{
"questionCode" : 3,
"answer" : "blabla.."
}
]
}
If that's an option for you I shall happily provide you the right update statement for this layout, too.
Well, after some trials here is a c&p complete and full method to change an array's element by a given index:
public boolean changeArrayValue(DB db, String collectionName, long id, String arrayNameKey, int index, Object newValue)
{
DBCollection collection = db.getCollection(collectionName);
DBObject query = new BasicDBObject("id",id);//unique id is recommended
DBObject update = new BasicDBObject("$set", new BasicDBObject(arrayNameKey+"."+index, newValue));
DBObject result = collection.findAndModify(query, null, null, false, update,true, true);
//Just for precaution
if(result == null)
return false;
return (((BasicDBList)result.get(arrayNameKey)).get(index)).equals(newValue);
}
As you can see the main issue lays in the $set line here: arrayNameKey+"."+index .
In the result I've put the needed flags to get the updated result, which is of type BasicDBList<Object>.
Pleases note that you'll have to add all the needed checks and validations according to your taste.
Enjoy..

Parse where clause query from Rest Get call

I am receiving a where clause from Rest API Get and I should convert properties, So I need to convert this string to java object with logical and .... for example :
String where = "prop = 1 and prop2 = 'ssdf' or date > 20121204";
Is there any java library that converts where clause to java object with separate condition and operator ?
Finally I found this library :
https://github.com/JSQLParser/JSqlParser
Seems like very good for query parsing
Using JSqlParser one could use an already implemented utility method to parse conditions like in your where clause:
String where = "prop = 1 and prop2 = 'ssdf' or date > 20121204";
Expression expr = CCJSqlParserUtil.parseCondExpression(where);
System.out.println(expr);
This works with JSqlParser V0.9.x (https://github.com/JSQLParser/JSqlParser)
Then you have an object tree with separated operators, ands, ors, values. This one you could traverse using the ExpressionVisitorAdapter, e.g.
ExpressionVisitorAdapter visitor = new ExpressionVisitorAdapter() {
#Override
public void visit(Column column) {
System.out.println(column);
}
};
expr.accept(visitor);

Parse List<Object> on java beanutils.populate

I'm new at java beanutils and i'm getting a really hard time to figure out how can i accomplish this.
I can get all fields from Html FORM, an populate with beanutils.populate(Object, request.getParamterMap());
All works, even fields mapped as "CustomClass someobj", i had a little trouble but with form input field nominate as "someobj.field" i can get its right.
Now i need to do a map as List listobj but i dont know how.
Tried in form name as "listobj[].field", "listobj.[].field", "listobj.[]field", "listobj[][field]", but none of this work. I can do it manually via setProperty("listobj",List<CustomClass>);
I got it.
For anyone with the same problem, what i did was:
In Html form
name="indexedListobj[listobj.id].field"
I'm using hibernate so my object are now Set<CustomClass> listobj instead of List<CustomClass> listobj to prevent collection exception.
What i did was to create another method for check an index against objects in Set, then, update object if exists, or append a new if not. like this:
public CustomClass getindexedListobj(int index) {
CustomClass tmp = null;
for(CustomClass o : this.listobj)
if(o.getId() == index) {
tmp = o;
break;
}
if(tmp == null) {
tmp = new CustomClass();
this.listobj.add(tmp);
}
return tmp;
}

How can i directly acess embedded document object mongodb

Here is my document
{
"_id":"1000",
"event_name":"Some name",
"tracks":
[
{
"id":"100"
"title":"Test title",
},
{
"id":"101"
"title":"Test title 2",
}
]
}
I want to directly acess track with id 101
So far i am doing this
Query query = new Query(Criteria.where("tracks.$._id").is(id));
// Execute the query and find one matching entry
Event event= mongoTemplate.findOne(query, Event.class,MongoDBCollections.EVENT);
I want some thing like this
Track track = event.getTrackById(id); how can i get track from that event object?
You are using the positional operator in the wrong place, it is a "projection" modifier and is not part of the query. You add the fields on the query spec with the .include() method:
Query query = new Query(Criteria.where("tracks._id").is(id);
query.fields().include("tracks.$");
Event event = mongoTemplate.findOne(query,Event.class,MongoDBCollections.EVENT);
But as with all projecton, the list of "fields" is all or nothing. So you either specify all of the fields to match your result class or modify that result class to just the fields you wish to return.

Processing: how to check if JSON Objects are bound

Since the Processing forum is down I hope one of you guys can help me out.
I made a Processing sketch that pulls data from an API (test here: http://www.europeana.eu/portal/api/console.html ) in JSON-format and reads some fields of this data for visualization. Everything works fine so far except when there are fields that are not bound to every JSONObject.
This is the code for the retrieval of the data:
JSONObject json;
json = loadJSONObject("data.json"); // loading my JSON file into the object
JSONArray CHOData = json.getJSONArray("items"); // array of the items I want data from
for (int i = 0; i < CHOData.size(); i++) {
JSONObject CHO = CHOData.getJSONObject(i); // get a specific item
JSONArray previewObj = CHO.getJSONArray("edmPreview"); // this field is an array, so I need to store it in a JSONArray object first
String[] previewArray = previewObj.getStringArray(); // here I store it in my actual string array
String preview = previewArray[0]; // I only need the first element
}
As you can see, I want the first string of the "edmPreview" array in the object. When I run the sketch, I get an error: "JSONObject["edmPreview"] not found."
This is of course because not every item has such an object. But how can I test if there is an object with this name in an item? I tried with if(CHO.getJSONObject("edmPreview") != null), but same error. Is there a way to look into the JSONObject and check the data values for something called "edmPreview"? There is no such function explained in the Processing reference.
The JSON file essentially looks as follows:
{
"items": [
{
"id": "someID",
"edmPreview": [
"http://europeanastatic.eu/api/image?uri=someimage.jpg"
],
// some other fields
}, // some other items
]
}
I'm new to this JSON-stuff, so maybe I miss something important... Thanks for the help!
So I found the answer myself, but not in the Processing reference, but in the actual reference for the JSONObject class in Java (http://www.json.org/javadoc/org/json/JSONObject.html). I tried some of the methods there and found that hasKey() (which is actually something I came up with myself, combining the method "has()" with the term "key", pure coincidence) as a boolean value works very well:
String preview = "";
if (CHO.hasKey("edmPreview")) {
JSONArray previewObj = CHO.getJSONArray("edmPreview");
String[] previewArray = previewObj.getStringArray();
preview = previewArray[0];
}
So now I learned that Processing is essentially just Java and sometimes not every method is written in the Reference. :-)

Categories