JSONPath get value from map within a table - java

I have a JSON string as follows (simplified):
{
"data":{
"fruit":[
{
"role":[
{
"role":"passive"
}
],
"objectType":"apple"
},
{
"role":[
{
"role":"active"
}
],
"objectType":"orange"
}
]
}
}
I would like to get objectType value where role is active. In this example the result would be orange. I've come up with the following code, however it doesn't return anything. How do I fix this?
$.data.fruit[?(#.role.role == 'active')]
Note that the number of elements in fruit array may vary and there is no guarantee that the last element would be correct.

At OP's request, here's the final, final answer!
$.data.fruit[?('active' in #..role..role)].objectType

On the off chance that it is a number, progressive levels in the stringification will each be indented by this many space characters (up to 10).
In the event that it is a string, progressive levels will be indented by this string (or its initial ten characters).

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..

How to reduce the length of a multivalued field in Solr

We have a multivalued field in Solr that we want to reduce its length.
A sample result response is as follows:
response": {
"numFound": 1,
"start": 0,
"docs": [
{
"created_date": "2016-11-23T13:47:46.55Z",
"solr_index_date": "2016-12-01T08:21:59.78Z",
"modified_date": "2016-12-13T08:45:44.507Z",
"id": "FEAE38C2-ABFF-4F0C-8AFD-9B8F51036D8A",
"Field1": [
"false",
"true",
"true",
..... <= 1200 items
]
}
]
}
We have big data, a couple of TB and we are looking for an optimized way to alter all documents within Solr and to modify Field1 to contain only the first 100 items.
Can something like this be done without the need to write a script to manually fetch the document, make adjustments and push it back to solr? Has anyone had a similar experience? Thanks
We have faced this problem. But we use Two collections to solve this problem. Use SoleEntityProcessor to move the document from one collection to another.
[SolrEntityProcessor]
<dataConfig>
<document>
<entity name="sep" processor="SolrEntityProcessor" url="http://localhost:8983/solr/db" query="*:*"/>
</document>
</dataConfig>
While moving pass that document through updateRequestProcessorChain where we can write StatelessScriptUpdateProcessorFactory to edit our documents or to truncate the multivalued field.
In StatelessScriptUpdateProcessorFactory you can get the field and apply your operations and then reset that field.
[StatelessScriptUpdateProcessorFactory]
function processAdd(cmd) {
doc = cmd.solrDoc;
multiDate = doc.getFieldValue("multiValueField");
//Apply your operation to above field
//doc.setField("multiValueField",value);
}
function processDelete(cmd) {
// no-op
}
function processMergeIndexes(cmd) {
// no-op
}
function processCommit(cmd) {
// no-op
}
function processRollback(cmd) {
// no-op
}
function finish() {
// no-op
}
For More information on StatelessScriptUpdateProcessorFactory, you can refer to this question
On solr how can i copy selected values only from multi valued field to another multi valued field?
in which they edit the multivalued field using the script.

How to store data from When statement in Drools?

I need the data that caused the rule to be fired from the "When" section in the "Then" section of the rule. For instance, if I wanted to make note of all bad apples in a store if there were more than 50, this is how I'm doing it.
Rule "Detect Bad Apples"
When
s : Store( numberOfBadApples() > 50 )
Then
// Print out a list of the bad apples
To make it a little more complicated I have multiple rules that will overwrite. Otherwise, I would store the data into a variable in the Store class.
Is there a better way to do this? I've been reading through the Drools 6.2 Documentation, but I'm still confused.
---EDIT----
The Store Class in Java would look like:
public class Store {
private ArrayList<Apple> appleList;
// The appleList would be filled in another method
public int numberOfBadApples() {
int badAppleCount = 0;
for (Apple apple : appleList) {
if (apple.isBad()) {
badAppleCount++;
}
}
return badAppleCount;
}
}
So in the "Then" statement in Drools, I want to return a list of the apples (the bad ones, in this case) that caused the rule to be fired.

saving only doubledigit numbers into my attribute

I got a task for a Season Object which can only save doubledigit integer numbers as the season number.
How can I initialize the value properly so it will only store doubledigit numbers?
I'm not allowed to use methods or my constructor for that.
the only possible solution I found (even though it would be dumb) is to use an enum from 1 to 99.
Is this really the solution? I'm also not allowed to use API classes for that.
Edit:
public class Season {
String name;
Series series;
int seasonNumber;
public Season () { }
}
I didn't post the code on purpose cause it isn't anything that will help
Edit2: (Tl;Dr of the Task)
The Task is to create a Series, Season and Episode Object. Series and Episode aren't of interest as for this question. The Season Object is defined as you can see in the code above.
The overall conditions are as following:
- primitive datatypes, String, enum are allowed and every class I wrote myself.
- no API classes are allowed.
- methods aren't needed.
- constructor isn't allowed to modify my number with regEx or anything like that
This is the best solution I can come up with:
public Season(int seasonNumber) {
if (seasonNumber < 1 || seasonNumber > 99) {
throw new IllegalArgumentException("Value between 1 and 99 (both inclusive) required. Found + " seasonNumber);
}
this.seasonNumber = seasonNumber;
}
I am not using a method, because the logic is all in the constructor. Though I suspect the person who gave you this hasn't got his point across with the assignment texts.
If you want the season number returned as 01, 02, etc., you could create a method that returns a String, instead of an int:
public String getSeasonNumber() {
if (seasonNumber < 10) {
return "0" + seasonNumber;
} else {
return seasonNumber;
}
}

Multidimensional array in java

I have create following string multidimensional array in java. which has top outer array is level(6 levels)and under each level has 4 different sub-level(4 sub levels) and each group has individual 10 set ,that have head and tails.I want to access level1->>sublevel1->set1-->head and tails ...level3->group4->set7->head and tails and so on up to level6->sublevel4->set10->head and tails.
final String[][][][] myStr = {
{
{
{"it", "it was over"},
{"on","work on it"},
},
{
{"very", "very good girl"},
{"all","all around"},
},
{
{
{"for", "good for you"},
{"are","are so long"},
},
{
{"with","with his cat"},
{"it", "it was over"},
}
},
...
{
{
{"get","get the cat"},
{"for", "good for you"},
},
{
{"on","work on it"},
{"can","can come here"},
},
{
{"as","as long as"},
{"but", "but not me"},
},
{
{"aunt","was my aunt"},
{"system", "her system was"},
}
}
};
Help me this problem , i think which is great appreciate to me.
Whatever your problem is, you shouldn't use such a kind of array, because your code will be impossible to understand and unmaintainable.
You should create a Level class, which would give access to a set or list of SubLevel instances, which should give you access to a set or list of Group instances, etc.
This will lead to much more readable code, and allow you to encapsulate behavior in these classes.
Say no to multi-dimensional array, Instead create custom classes if the relation is complex, else use simple Map.
I have no idea what you're actually trying to do, but it looks like you want to do a map from words to the sentence fragment it was found in - try a HashMap<String,String>

Categories