I am trying to update an es document using Java.
My document is as follows
"_source": {
"gender": "male" ,
"names": ["name1"]
}
I need to add more names to names list. But I want no duplicates.
How can I update an array in an ES document without duplicate values?
I tried something like this. But it's not working.
client.prepareUpdate(index,type,id)
.addScriptParam("newobject", "newName")
.setScript("ctx._source.names.contains(newobject) ? ctx.op = \"none\" : ctx._source.names+=newobject ").execute().actionGet();
The idea would be to simply call unique() on the resulting list:
client.prepareUpdate(index,type,id)
.addScriptParam("newobject", "newName")
.setScript("ctx._source.names+=newobject; ctx._source.names = ctx._source.names.unique(); ").execute().actionGet();
Also for this to work, you need to make sure that scripting is enabled.
Related
I have a JSON which has an attribute with its List type. Can someone help me on how to read the value in Apache Velocity template? Following is an example of JSON. The challenge is to read the list of University from JSON and iterate through it.
{
"StudentName":"XYZ",
"List<Univesity>": [
{
"Name": "NYU",
"City": "NY",
"Country":"US",
} ]
}
The solution is dependent upon the JSON library you use, but for many of them, the following code should work:
#set( $universities = $document.get('List<University>') )
#foreach( $university in $universities )
... do something ...
#end
The main point to note here is that you can call any Java method on the object you get.
Also, if the security uberspector is not present, for debugging purposes you can display the Java class name of any object in the context, for instance: $document.class.name should display, in your case, something like com.fasterxml.jackson.databind.node.ObjectNode.
I have this document
It contains this array of document named reviews
I tried this code to get the review that were posted by Théo but it keeps returning me the whole document (including sub-documents in reviews) not the one I'm specifing by with Filters.
Document document = collection.find(Filters.and(Filters.eq("reviews.reviewer_name", "Théo"))).first();
I really can't understand how to get only this specific document. Thanks for any help
If you're trying to do sub-document queries & only retrieve specific sub-documents, there's no way to do that with mongo's simple queries. However, you can use the aggregate pipeline to achieve this.
db.collection.aggregate([
// This is the same as your initial find query, it will limit the top-level docs to only be the ones you are interested in
{ $match: { 'reviewers.reviewer_name': 'Theo' } },
// You can now unwind the results, which will make all the sub-documents top-level
{ $unwind: '$reviewers' },
// Re-match to filter the reviewers, this will actually drop the unmatched reviewers
{ $match: { 'reviewers.reviewer_name': 'Theo' } },
// Now you can use a projection to get the final results you are looking for
{ $project: { reviewer: '$reviewers' } }
])
This will return an array of objects with a reviewer property, each element containing a single review. You can then use the pagination stages to trim the results:
db.collection.aggregate([
// ... same stages as above, and then:
{ $limit: 1 },
])
Not sure what the specific data structures would be with the Java driver you are using, but these are the general mongo queries that will do the trick.
If you want to read more about the aggregate pipeline, I recommend checking out the official documentation which is so awesome that I have it opened all day. They should have some Java examples on there.
Best of luck!
Please consider a MongoDB collection with the following document:
"_id": "clientsInfo"
"data": {
"clientsList" : [
{
"name" : "Mike",
"country" : "USA"
},
...
]
}
After setting the DataSet and defining the Query like this...
{
collectionName:'projectA',
findQuery: {
'_id':'clientsInfo',
},
findFields: {
'_id':0,
'data.clientsList':1
},
}
...I am able to display the first item of the fetched array (java.util.List type) in JasperSoft Studio inside a Text Field using the following expression:
$F{data.clientsList}.get(0)
But, considering that I would like to exhibit the whole data in a Name/Country Table...
Question1: How could I access any of the dictionary fields? Trying get method I obtain The method get(String) is undefined for the type Object. error. However, knowing that the object is an instance of com.mongodb.BasicDBObject it should have that method inherited (See doc).
I have also tried to cast object to org.json.JSONObject but then I get net.sf.jasperreports.engine.fill.JRExpressionEvalException: Error evaluating expression for source text: (JSONObject)$F{data.clientsList}.get(0) error.
Question2: Let's suppose we have already solved first question... How can I iterate the list to access not only the first item but all of them according to the array length? Is it possible to use for-loop sentence inside the JasperSoft Expression Editor? (if-then-else seems to be available)
Thanks in advance, Any clue that point me in the right direction will be appreciated.
Just in case someone was in the same situation as I was, I must say this whole approach was wrong.
It's not about making a simple query which returns big block of complex data formatted as an object or list of objects and then manipulate it with JasperSoft Studio. Instead, what I had to do was design a more elaborated query which returns the simple fields I wanted to use straightforward. How to do this? By using Aggregation Framework.
So, by changing this...
{
collectionName:'projectA',
findQuery: {
'_id':'clientsInfo',
},
findFields: {
'_id':0,
'data.clientsList':1
},
}
...for this...
{
runCommand: {
aggregate : 'projectA',
pipeline : [
{'$match': {'_id':'clientsInfo'}},
{'$project': {'data.clientsList': 1}},
{'$unwind': '$data'},
{'$unwind': '$data.clientsList'}
]
}
}
...is how I get name and country fields in order to use them in Text Fields, Tables, ...etc.
Let's say that we have the following json response:
{
"data":
[
{
"id": 1,
"name": "Pablo"
},
{
"id": 2,
"name": "Ernesto"
}
]
...
}
Where the data list could consist of many more objects. If I where to verify that no name field is set to null, what would be the Rest Assured way of doing this?
Now I'm using:
from(response.asString()).get("data");
to get a list of HashMaps, and then moving on from there for each entry. But I guess there is some other way that is more efficient?
Edit/Clarification: I am wondering if there is a way to do this without the creation of a list of maps?
i guess this is the best we can do
List<HashMap> data = from(response.asString()).get("data");
for(HashMap map: data){
if(map.get("name") == null){
// null name found
}
}
// No null name found
Ok, so perhaps I should have read the docs a bit more carefully, the easiest (and intended) way to retrieve e.g. all name values (as in my example) is to use JsonPath like so:
List<Object> names = from(response.asString()).get("data.name");
So there are no magical utility methods within the Rest-Assured library to do this except using JsonPath.from().get() and then to go from there.
I am working on a Spring MVC and I want to insert javascript into the html output for analytics purpose. I am only partially familiar with serialization but I figured it does the job nicely rather than manually constructing a string containing javascript.
Would it be possible to generate something the following snippet? Any pointers would be great!
"emd" : new Date('6/6/2014')
Update:
I need to output a javascript object which has many fields which may be complex. Hence, on the backend I am gathering all the data into java beans with all the information and I plan to use Jackson mapper to convert to string that I can just output through JSP.
Generating the above snippet does not seem straightforward though, not sure if it is even possible. For context, the rest of that javascript looks something like this.
Analytics.items["item_123"] = {
//ratings and reviews
"rat" : a.b, //the decimal value for the rating
"rev" : xxxx, //integer
//list of flags that indicate how the product was displayed to the customer
//add as needed...tracking code will pick up flags as needed when they are available
"dec" : ["mbe", "green", "recycled"],
//delivery messaging
"delivery" : {
"cd" : new Date() //current date
"offers" : [{
"type" : "abcd"
"emd" : new Date('6/6/2014'),
"weekend" : true
}
]
},
};
JSON.stringify should do the trick. It will be built into your browser, unless you're using a very old browser, in which case you can use a polyfill.