Embedded Array Retrieval Mongodb Java - java

I've been trying to get this query, but I have been unable to roll my heads over this one.
The Object looks like this:
{
restaurantName:'abc',
reviews:[
{
text:'Its awesome!'
person: 'John Doe'
}
{
text:'Nice Ambience'
person: 'Davis'
}
]
}
The intent is to find out all the reviews text present in the document. How do I do this using JAVA driver for Mongo. I keep getting Class Cast Exceptions
Following is the code:
Set fields = new TreeSet();
BasicDBList e ;
try {
DBObject dbObject;
while (cursor.hasNext()) {
doc = new Document();
e = (BasicDBList) cursor.next().get("reviews");
for(BasicDBObject temp: e){
fields.addAll(temp.keySet());
}
}
//System.out.println(cursor.next());
}
The error I am getting is:
Exception in thread "main" java.lang.ClassCastException: com.mongodb.BasicDBObject cannot be cast to java.util.ArrayList at org.poly.darshan.utils.DataExtractor.main(DataExtractor.java:57)
The code mentioned above intends to find the unique fields present in the sub-objects. But the problem is more or less the same.

Ok found the Solution. In my case I know the field names, so I can retrieve the DBObject and then check for each field name and typecast it accordingly to retrieve it. *Wonders how free the wonderland of Javascript is. Luckily in Java, we mostly always know what we are going to get.:)
The solution looks something like this:
while (cursor.hasNext()) {
doc = new Document();
e = cursor.next();
for (String field : e.keySet()) {
if (field.equals("reviews")) {
BSONObject temp = (BSONObject) e.get(field);
System.out.println(temp.toString());
}
//else print the other String values
}
}
If BSOONList is retrieved, then typecast it accordingly. BSONList may contain BSONList or BSONObject, so it gets messy if you dont know what you want to retrieve. Dynamic Typecasting is helpful in these cases.

Related

How to check if a property exists in a JSONObject without calling .getJSONObject(key) several times?

I'm processing deeply nested JSON data. Here is a shortened example:
{
"timestamp":"123",
"layers":{
"frame_raw":"123",
"frame":{
"frame_frame_interface_id":"0",
"frame_interface_id_frame_interface_name":"asd",
...
},
"eth_raw":"123",
"eth":{
"eth_eth_dst_raw":"asd",
"eth_eth_dst":"asd",
...
},
"ip_raw":"123",
"ip":{
"ip_ip_version_raw":"4",
"ip_ip_version":"4",
"ip_ip_addr_raw":[
"asd",
"asd"
],
"ip_ip_addr":[
"1.1.1.1",
"1.1.1.1"
],
"ip_ip_dst_host":"1.1.1.1"
}
...
}
...
}
I have a list of structures that I explicitly allow. All others should be deleted from the JSON. An example for the list:
###frame###
layers.frame_raw
###eth###
layers.eth.eth_eth_dst
layers.eth.eth_eth_src
###ip###
layers.ip.ip_ip_src
layers.ip.ip_ip_dst
layers.ip.ip_ip_src_host
layers.ip.ip_ip_dst_host
layers.ip.ip_ip_version
layers.ip.ip_ip_hdr_len
layers.ip.ip_ip_dsfield
My problem is that I can only navigate through the JSON structure using "getJSONObject(key)".
How can I generate the path of the lowest elements of my JSON structure in the form "key.key.key..." so that I can match it with my list?
JSON object has a method called .has which will return a boolean value. So the logic is like to check whether the JSON object exists. If so check the child node for more existence of your data. If there is an array you have to get the array and migrate through the array using any loop and do the same. For example:
if (json.has("ip")) {
JSONObject jsonObject = getJSONObject.getString("ip")
String ip_ip_version_raw = jsonObject.getString("ip_ip_version_raw"));
if (jsonObject.has("ip_ip_addr_raw")){
JSONArray ip_ip_addr_raw = jsonObject.getJSONArray("ip_ip_addr_raw");
for (String s : ip_ip_addr_raw) {
...
}
}
}
For reference :
http://developer.android.com/reference/org/json/JSONObject.html#has(java.lang.String)
If you want to check the existence of a property of a JSONObject there is a method called has. This is the link to the official documentation.
I found a solution because the structure in my special case is always layers.layer.property, so the depth of the structure is always the same and not variable.
For interested people:
for (Iterator<String> layersIterator = jsonObject.getJSONObject("layers").keys(); layersIterator.hasNext(); ) {
String layer = layersIterator.next();
for (Iterator<String> propertyIterator = jsonObject.getJSONObject("layers").getJSONObject(layer).keys(); propertyIterator.hasNext(); ) {
String property = propertyIterator.next();
System.out.println("layers."+layer+"."+property);
}
}

Extract Object Data into usable format

I am a real newbie so go easy on me and my terminology, I am still learning!
I have a Backendless database I would like to show in my app.
I have successfully connected it to my Android Studio app, queried it and returned the data in the following method:
Backendless.Data.of( "database" ).find( queryBuilder, new AsyncCallback>(){public void handleResponse(List'<'Map'>'response ){
The narrative on the Backendless SDK says "the "response" object is a collection of java.util.Map objects"
I then used an iterator:
Iterator itr = response.iterator();
And a while loop to 'get' the object:
Object element = itr.next();
I am happy up until this point, the next step is to extract the useful data from element.
I have tried many options of but the only one I have working is element.toString() and use various methods to pick out what I want. This seems so inefficient I thought I would ask the experts for a better option!?
Your question is rather about working with Java Map interface. So I'd advice you to look into its documentation and maybe some tutorials on this topic.
As to your Backendless question, it looks like you got the request part right. Here is the extended example from the docs, which shows you how to retrieve the object fields:
Backendless.Persistence.of( "Contact" ).find( new AsyncCallback<List<Map<String, Object>>>(){
#Override
public void handleResponse( List<Map<String, Object>> foundContacts )
{
Iterator<Map<String, Object>> contactsIterator = foundContacts.iterator();
while( contactsIterator.hasNext() )
{
Map<String, Object> contact = contactsIterator.next();
String name = (String) contact.get( "name" ); // in case you have STRING field 'name' in Backendless database
Integer age = (Integer) contact.get( "age" ); // in case you have INT field 'age' in Backendless database
// etc.
}
}
#Override
public void handleFault( BackendlessFault fault )
{
System.out.err( "Failed find: " + fault );
}
});
As you may see, the main concern is to retrieve a Map instead of Object from the response List.
And also your question would be more useful with code samples of what you tried and maybe direct link to the docs you used as an example.

Updating pre-existing documents in mongoDB java driver when you've changed document structure

I've got a database of playerdata that has some pre-existing fields from previous versions of the program. Example out-dated document:
{
"playername": "foo"
}
but a player document generated under the new version would look like this:
{
"playername": "bar",
"playercurrency": 20
}
the issue is that if I try to query playercurrency on foo I get a NullPointerException because playercurrency doesn't exist for foo. I want to add the playercurrency field to foo without disturbing any other data that could be stored in foo. I've tried some code using $exists Example:
players.updateOne(new Document("playername", "foo"), new Document("$exists", new Document("playername", "")));
players.updateOne(new Document("playername", "foo"), new Document("$exists", new Document("playercurrency", 20)));
My thought is that it updates only playercurrency because it doesn't exist and it would leave playername alone becuase it exists. I might be using exists horribly wrong, and if so please do let me know because this is one of my first MongoDB projects and I would like to learn as much as I possibly can.
Do you have to do this with java? Whenever I add a new field that I want to be required I just use the command line to migrate all existing documents. This will loop through all players that don't have a playercurrency and set it to 0 (change to whatever default you want):
db.players.find({playercurrency:null}).forEach(function(player) {
player.playercurrency = 0; // or whatever default value
db.players.save(player);
});
This will result in you having the following documents:
{
"playername" : "foo",
"playercurrency" : 0
}
{
"playername" : "bar",
"playercurrency" : 20
}
So I know that it is normally frowned upon on answering your own question, but nobody really posted what I ended up doing I would like to take this time to thank #Mark Watson for answering and ultimately guiding me to finding my answer.
Since checking if a certain field is null doesn't work in the MongoDB Java Driver I needed to find a different way to know when something is primed for an update. So after a little bit of research I stumbled upon this question which helped me come up with this code:
private static void updateValue(final String name, final Object defaultValue, final UUID key) {
if (!exists(name, key)) {
FindIterable iterable = players.find(new Document("_id", key));
iterable.forEach(new Block<Document>() {
#Override
public void apply(Document document) {
players.updateOne(new Document("_id", key), new Document("$set", new Document(name, defaultValue)));
}
});
}
}
private static boolean exists(String name, UUID key) {
Document query = new Document(name, new Document("$exists", true)).append("_id", key);
return players.count(query) == 1;
}
Obviously this is a little specialized to what I wanted to do, but with little revisions it can be easliy changed to work with anything you might need. Make sure to replace players with your Collection object.

JSONObject when element doesn't exist

I have a struts action receiving following JSON:
{
"commandId":"tC",
"id":"123",
"def":""
}
Following code works just fine:
JSONObject command = null;
String commandId = null;
String deviceId = null;
try {
command = new JSONObject(json);
commandId = command.getString("commandId");
}
Since "def" can be empty, non declared or can contain another array of elements I tried doing this:
JSONObject def = command.getJSONObject("def");
in order to get this JSON object defined in the element def
This only works if def isn't empty like in this example:
{
"commandId":"tC",
"id":"123",
"def":{"1":"aaa", "2":"bbb"}
}
When def is empty or not defined my program stops working on the line JSONObject def = command.getJSONObject("def"); and noticed that it doesn't continue the execution?!
If I put JSONObject def = command.getJSONObject("def"); try / catch block I get _JSONObject["def"] is not a JSONObject _ exception, but execution doesn't continue
How does JSONObject.getJsonObject(String) behave?
I would expect it to return an empty JSONObject and continue the execution.
What I want is to check if there is anything defined in def and then in a if, else decide what to do in my program according to the value found there... I can't find a way to make my program work if a client's json comes with def empty or not defined.
my suggestion is to define "def" either be defined as null or {}:
"def":null or "def":{} to align with its usage agreement
quotes is really just used to indicate the value is a string. following the standard might save you and others from confusion in the future.
Likely it is because it is trying to get a Object and finding a string. In your JSON (if you control it), for an empty object I would do {}. This should allow Java to think it is retrieving an object.
If def is intended to be an object is it not suppose to look like this when empty?
{
"commandId":"tC",
"id":"123",
"def":{}
}
I think having "def":"" will cause the value to be attempted to be parsed as a string value and not an object value.
Maybe this will help someone. I had to solve the same problem. In my case the web service was returning empty JSON objects if it couldn't find the requested record.
Note: the data names have been changed to protect the innocent...
Note 2: this example uses javax.json
import javax.json.*;
JsonObject _jObj = _myRootObj.getJsonObject("someDataNode");
// at this point in execution _jObj could equal {"DataReturn":""}
// or {"DataReturn":"<some valid data>"}
// we want to test the existence of DataReturn before trying to
// use it
JsonValue jv = _jObj.getOrDefault("DataReturn", null);
String js = jv.toString();
// cover all the bases. test the value
if (js == null || js.isEmpty() || js.compareTo("\"\"") == 0)
{
throw new Exception("Error: DataReturn object null. Cannot proceed.");
}
// the object exists, so it's ok to get it
JsonObject jObjDate = _jObj.getJsonObject("DataReturn");
If you're using org.json.JSONObject you can use .isNull(String key) to do this, something like:
if (command.isNull("def") {
// Handle 'def' not being there
} else {
JSONObject def = command.getJSONObject("def");
}

Can not understand the result of request JPA

I have a function that return an ArrayList< String > ,the list contain elements retrieved from database using JPA ,my problem is that I can't understand the format of the output!
the function is:
public ArrayList<String> getMyListEnvironment()
{
ArrayList<String> env=new ArrayList<String>();
try{
EntityTransaction entr=em.getTransaction();
entr.begin();
javax.persistence.Query multipleSelect= em.createQuery("SELECT h.hEnv FROM HPe h WHERE h.hPePK.pePlatform = :w ").setParameter("w", "platf1");
List s = new LinkedList();
s= multipleSelect.getResultList();
env = new ArrayList(s);
entr.commit();
return env;
}
catch (Exception e )
{
System.out.println(e.getMessage());
System.out.println("error");
}
finally {
em.close();
}
return env;
}
The output(Result):
[DTOMonito.HEnv[ envUrl=http://10.55.99.5:1055 ], DTOMonito.HEnv[ envUrl=http://10.55.99.99:8090 ]]
The query is returning the list of hEnv found as fields of the the HPe entity (seems like these abbreviations for the entities cause more confusion than good - it's a good idea to use descriptive names for these type of things).
Is HPe.hEnv a String? Perhaps your output is confusing because someone is storing a formatted string in this field. Without seeing your code, this is very hard to decipher.
Btw, this method is a bit wasteful for creating dead stores. There is absolutely no point in writing something like this:
List s = new LinkedList();
s= multipleSelect.getResultList();
You could save a line of code (and a LinkedList allocation) by just writing
List s = multipleSelect.getResultList();

Categories

Resources