MongoDB java driver using regex query to retrieve first two character - java

i want to retrieve first two character value like if i give 02-01-2017 00:05:46 i should get result like
02-01-2017 00:05:46
02-01-2017 00:05:46
02-01-2017 00:05:46
Without string SyTime_000_09_00:00
i am using jongo library and mongo drive 3.4.2
{
"_id" : ObjectId("590b70c609200535e85c6540"),
"Data" : "02-01-2017 00:05:46 SyTime_000_09_00:00 "
}
{
"_id" : ObjectId("590b70c609200535e85c6541"),
"Data" : "02-01-2017 00:05:46 DPMPow_P01_04_ 45.53 "
}
Here is what i have tried
public class DataSource {
private MongoCollection collection;
public void DataSource() {
this.collection = (new Jongo(new
MongoClient("localhost", 27017).getDB("admin"))).getCollection("test");
}
public void guarder(Object obj) {
this.collection.save(obj);
}
public Iterable consol() {
DBObject query = new BasicDBObject();
Pattern regex = Pattern.compile("02-01-2017");
query.put("Data", regex);
return (Iterable) this.collection.find(query.toString()).as(pojo.class);
}
}
here is pojo class
public class pojo {
#MongoObjectId
String _id;
String Data;
public pojo() {
}
public pojo(String Data) {
this.Data = Data;
}
public String getData() {
return Data;
}
public String getId() {
return _id;
}
}
i am using jframe Button Action GUi
private void findActionPerformed(java.awt.event.ActionEvent evt) {
try{
DefaultListModel listModel = new DefaultListModel();
DataSource ds=new DataSource();
ds.DataSource();
Iterable pojo=ds.consol();
pojo p;
int i=0;
for (Iterator it=pojo.iterator();it.hasNext();){
p = (pojo)it.next();
listModel.addElement(p.getData());
}
mdata.setModel(listModel); //jlist
}catch(Exception e){
System.out.println(e);
}
}
Result

As stated by Wiktor Stribiżew
p.getData() returns a String that is added to the listModel. Use p.getData().replaceFirst("^(\S+\s\S+).*", "$1")

Related

JSON String to Java String

I have these JSON String:
{
"Results": {
"output1": {
"type": "table",
"value": {
"ColumnNames": ["userId", "documentId", "Scored Labels", "Scored Probabilities"],
"ColumnTypes": ["String", "String", "Boolean", "Double"],
"Values": [["100213199594809000000", "1Ktol-SWvAh8pnHG2O7HdPrfbEVZWX3Vf2YIPYXA_8gI", "False", "0.375048756599426"], ["103097844766994000000", "1jYsTPJH8gaIiATix9x34Ekcj31ifJMkPNb0RmxnuGxs", "True", "0.753859758377075"]]
}
}
}
}
And I want to have only the ColumnNames and the Values. I have tried it with something like this:
Map<String,Object> map = mapper.readValue(filename, Map.class);
String CN = (String) map.get("ColumnNames");
But then I get the following error:
Exception in thread "main" org.codehaus.jackson.JsonParseException: Unexpected character ('A' (code 65)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')
at [Source: java.io.StringReader#64232b15; line: 1, column: 2]`
I've worked only few times with JSON. Can anybody help me here?
The best case for me would be something like this, which I've done in another case:
String uId = (String) attr.get("userId");
Is it possible?
So now I've done this:
I try it like this:
public class ClientPOJO {
private String userId;
private String documentId;
public String getuserId() {
return userId;
}
public void setuserId(String userId) {
this.userId = userId;
}
public String getdocumentId() {
return documentId;
}
public void setdocumentId(String documentId) {
this.documentId = documentId;
}
}
and then:
ObjectMapper mapper = new ObjectMapper();
ClientPOJO clientes= mapper.readValue(filename, ClientPOJO.class);
String uid = clientes.getuserId();
But now when I make a Prtinout I'll get the same error like before:
Exception in thread "main" org.codehaus.jackson.JsonParseException: Unexpected character ('A' (code 65)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')
at [Source: java.io.StringReader#7a6eb29d; line: 1, column: 2]
Java- Convert JSON string into string / integer / Object
String jsonString = "{"username":"Gajender"}";
org.json.JSONObject jsonObj =new JSONObject(jsonString);
String name = (String) jsonObj.get("username").toString();
Below is an example to illustrate a generic approach to solve your problem ( based on Jackson library). You may like to enhance the solution to meet your all requirements.
Comments inlined.
package com.stackoverflow;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
// Junit class
public class TableDeserExample {
// sample input
String inputJson = "{\n" +
" \"Results\": {\n" +
" \"output1\": {\n" +
" \"type\": \"table\",\n" +
" \"value\": {\n" +
" \"ColumnNames\": [\"userId\", \"documentId\", \"Scored Labels\", \"Scored Probabilities\"],\n" +
" \"ColumnTypes\": [\"String\", \"String\", \"Boolean\", \"Double\"],\n" +
" \"Values\": [[\"100213199594809000000\", \"1Ktol-SWvAh8pnHG2O7HdPrfbEVZWX3Vf2YIPYXA_8gI\", \"False\", \"0.375048756599426\"], [\"103097844766994000000\", \"1jYsTPJH8gaIiATix9x34Ekcj31ifJMkPNb0RmxnuGxs\", \"True\", \"0.753859758377075\"]]\n"
+
" }\n" +
" }\n" +
" }\n" +
"}";
// POJO to map the Json structure. You may want to make it generalize based
// on field "type"
// (https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization)
public static class Result {
private String type;
private TableResult value;
public String getType() {
return this.type;
}
public void setType(String type) {
this.type = type;
}
public void setValue(TableResult value) {
this.value = value;
}
public TableResult getValue() {
return this.value;
}
}
// Pojo for table result
public static class TableResult {
private List<String> columnNames;
private List<String> columnTypes;
private List<Object[]> values;
#JsonProperty("ColumnNames")
public List<String> getColumnNames() {
return this.columnNames;
}
public void setColumnNames(List<String> columnNames) {
this.columnNames = columnNames;
}
#JsonProperty("ColumnTypes")
public List<String> getColumnTypes() {
return this.columnTypes;
}
public void setColumnTypes(List<String> columnTypes) {
this.columnTypes = columnTypes;
}
#JsonProperty("Values")
public List<Object[]> getValues() {
return this.values;
}
public void setValues(List<Object[]> values) {
this.values = values;
}
}
// Top level Json POJO
public static class ResultContainer {
private Map<String, Result> results;
#JsonProperty("Results")
public Map<String, Result> getResults() {
return this.results;
}
public void setResults(Map<String, Result> results) {
this.results = results;
}
}
// A contract to map the result "values" to the expected object
public static interface ResultMapper<T> {
T map(TableResult map, Object[] row);
}
// Basic implementation for mapping user object from json "values[i]" array
public static class UserTableResultMapper implements ResultMapper<User> {
#Override
public User map(TableResult result, Object[] row) {
User user = new User();
// Here use any mapper logic based on column name
// Retrieved from result object.
// Below are for illustration only
user.setId(String.valueOf(row[0]));
user.setDocumentId(String.valueOf(row[1]));
return user;
}
}
// A result reader class
public static class ResultReader<T> implements Iterable<T> {
private TableResult result;
private ResultMapper<T> mapper;
public ResultReader(TableResult result, ResultMapper<T> mapper) {
this.result = result;
this.mapper = mapper;
}
#Override
public Iterator<T> iterator() {
final Iterator<Object[]> itr = result.getValues().iterator();
return new Iterator<T>() {
#Override
public void remove() {
throw new UnsupportedOperationException();
}
#Override
public T next() {
Object[] values = itr.next();
return mapper.map(result, values);
}
#Override
public boolean hasNext() {
return itr.hasNext();
}
};
};
}
public static class User {
private String id;
private String documentId;
// and others
public String getId() {
return this.id;
}
public void setDocumentId(String documentId) {
this.documentId = documentId;
}
public void setId(String id) {
this.id = id;
}
public String getDocumentId() {
return this.documentId;
}
}
#Test
public void simpleTest() throws Exception {
ObjectMapper mapper = new ObjectMapper();
ResultContainer file = mapper.readValue(inputJson, ResultContainer.class);
Result result = file.getResults().get("output1");
ResultReader<User> userResultReader = new ResultReader<>(result.getValue(), new UserTableResultMapper());
for (User user : userResultReader) {
System.out.println(user.getId() + " : " + user.getDocumentId());
}
}
}
If you know exactly the structure of your json (like the json you have post) then you can using Gson to get your object like this:
JsonParser parser = new JsonParser();
JsonObject json = (JsonObject) parser.parse("your_json_string_here");
String column = json.get("Results").getAsJsonObject().get("output1").getAsJsonObject().get("value").getAsJsonObject().get("ColumnNames").getAsJsonArray().toString();
String value = json.get("Results").getAsJsonObject().get("output1").getAsJsonObject().get("value").getAsJsonObject().get("Values").getAsJsonArray().toString();
System.out.println(column);
System.out.println(value);
If you need some things more generic then you can parse your json string to a HashMap<String, Object> then using recursion to read the HashMap and get the value you want.
Example (in my code, the type of Map will corresponding to a Json Object, type of List will corresponding to the Array in Json string):
Type type = new TypeToken<HashMap<String, Object>>() {}.getType();
Gson gson = new Gson();
HashMap<String, Object> map = gson.fromJson("your_json_string_here", type);
for (String key : map.keySet()) {
Object obj = map.get(key);
if (obj instanceof List) {
for (Object o : (List) obj) {
if (o instanceof Map) {
loop((Map) o);
} else {
System.out.println(key + " : " + o);
}
}
} else if (obj instanceof Map) {
loop((Map) obj);
} else {
System.out.println(key + " : " + obj);
}
}
}
private static void loop(Map<String, Object> map) {
for (String key : map.keySet()) {
Object obj = map.get(key);
if (obj instanceof List) {
for (Object o : (List) obj) {
if (o instanceof Map) {
loop((Map) o);
} else {
System.out.println(key + " : " + o);
}
}
} else if (obj instanceof Map) {
loop((Map) obj);
} else {
System.out.println(key + " : " + obj);
}
}
}
Neither Jackson nor any other library will parse the Values array into objects with client data like your POJO. You can achieve this by getting the raw tree of data in this JSON and constructing objects by iterating over the Values array inside this tree. Assuming the order of ColumnNames is fixed then you can parse with Jackson like this:
final ObjectMapper mapper = new ObjectMapper();
final JsonNode tree = mapper.readTree(json);
final JsonNode values = tree.findValue("Values");
final List<ClientPOJO> clients = new ArrayList<>();
for (JsonNode node : values) {
final ClientPOJO client = new ClientPOJO();
client.setUserId(node.get(0).asText());
client.setDocumentId(node.get(1).asText());
client.setScoredLabels(node.get(2).asBoolean());
client.setScoredProbabilities(node.get(3).asDouble());
clients.add(client);
}
Docs for JsonNode. Basically with findValue you can get another node deep into the tree, with get you can get array elements by index and with asText etc you parse a value in JSON into the appropriate type in Java.
Since you seem to be flexible in choice of JSON parsing library I would suggest Jackson 2 from com.fasterxml instead of Jackson 1 from org.codehaus that you tried.

Build dynamic JSON

I'm trying to build dynamic json request in java to send to my c++ server. I'm using the GSON library.
This is my json example:
{
"nodes": {
"12131231231231241": {
"gToken": {
"token": "AABBCCDDEEFF99001122334455667788"
},
"objects": {
"WATER_CONTROL_1": "0"
}
},
"7682642342432423": {
"userAuthentication": {
"userEmail": "user#mail.com",
"userPassword": "userPassword"
},
"objects": {
"LIGHT_1_CONTROL": "1"
}
}
}
}
If you can see the nodes object is dynamic. Inside him i can have a lot of items (in the example i put two, representing by 12131231231231241 and 7682642342432423). Inside each item the authentication method can be different (by token, by email/password) and inside objects item i can have a lot of different dynamic items too.
The part to send to my c++ server, parse the JSON and do the all validations (authetication for example) is already done and working (i test this json example inside c++ string, encode to json and do the parse, get the all items,etc).
So my problem is to build my class to send the request with some struct to corresponding to this dynamic json.
I already implement some other class to send json to my server and its work because i already know the json expected and on other cases the json have a static/fixed content.
My class for this dynamic json:
public class MonitorControlGetRequestArgs implements SerializableJSON {
Nodes nodes;
public MonitorControlGetRequestArgs() {
nodes = new Nodes();
}
static class Nodes{
public Nodes(){
}
}
public static MonitorControlGetRequestArgs fromStringJson(String data){
try {
Gson gson = new Gson();
return gson.fromJson(data, MonitorControlGetRequestArgs.class);
}
catch(Exception e){
return null;
}
}
public static MonitorControlGetRequestArgs fromBytesJson(byte[] data){
if (data == null)
return null;
try {
String str = new String(data, "utf-8");
return fromStringJson(str);
}
catch (Exception e) {
return null;
}
}
#Override
public String toJsonString(){
try{
Gson gson = new Gson();
return gson.toJson(this);
}
catch(Exception e){
return null;
}
}
#Override
public byte[] toJsonBytes(){
try {
return this.toJsonString().getBytes("utf-8");
}
catch (Exception e){
return null;
}
}
}
I create a static class Nodes empty to show you. In my server c++ i receive the item nodes in json format, but now i have a lot of doubts how to build the struct inside nodes to corresponding to my dynamic json.
I hope you understand my doubts. If you don't understand something tell to me.
EDIT 1 - (try to use the example of Andriy Rymar)
I try to simulate this json:
{
"nodes": {
"1317055040393017962": {
"userAuthentication": {
"userEmail": "rr#rr.com",
"userPassword": "rr123"
}
}
}
}
My request class:
public class MonitorControlGetRequestArgs implements SerializableJSON
{
private final static String nodeTemplate = "\"%s\":%s";
List nodes = new ArrayList<>();
public MonitorControlGetRequestArgs(UserAuthentication userAuthentication)
{
JsonData jsonData = new JsonData();
jsonData.addNode(new Node("1317055040393017962", new NodeObject(userAuthentication)));
}
static class Node
{
private final String nodeName;
private final Object nodeBody;
public Node(String nodeName, Object nodeBody) {
this.nodeName = nodeName;
this.nodeBody = nodeBody;
}
public String getNodeName() {
return nodeName;
}
public Object getNodeBody() {
return nodeBody;
}
}
static class JsonData {
List<Node> nodes = new ArrayList<>();
public void addNode(Node node){
nodes.add(node);
}
}
static class NodeObject
{
UserAuthentication userAuthentication;
public NodeObject(UserAuthentication userAuthentication)
{
this.userAuthentication = userAuthentication;
}
}
public static MonitorControlGetRequestArgs fromStringJson(String data)
{
try
{
Gson gson = new Gson();
return gson.fromJson(data, MonitorControlGetRequestArgs.class);
}
catch(Exception e)
{
return null;
}
}
public static MonitorControlGetRequestArgs fromBytesJson(byte[] data)
{
if (data == null) return null;
try
{
String str = new String(data, "utf-8");
return fromStringJson(str);
}
catch (Exception e)
{
return null;
}
}
#Override
public String toJsonString()
{
try
{
Gson gson = new Gson();
return gson.toJson(this);
}
catch(Exception e)
{
return null;
}
}
#Override
public byte[] toJsonBytes()
{
try
{
return this.toJsonString().getBytes("utf-8");
}
catch (Exception e)
{
return null;
}
}
}
EDIT 2
I will try to explain better,i believe I was not totally explicit. My application java is a REST application that send json to my c++ server. In my server i receive the json, i do the parse, i do the validation, the operations, etc and return back to my java client the response in json too.
For example, imagine that my json request body (to create a new user for example) is something like this:
{
"userInformation": {
"name": "user name",
"age": 33
}
}
For this i don't have any doubts how to do (i already implement a lot of requests very similar). I can create a static class like this:
static class UserInfo
{
String name;
String age;
public UserInfo(String name, String age)
{
this.name = name;
this.age = age;
}
}
And inside a request class (very similar to a class like i copy before - MonitorControlGetRequestArgs) i create a new instance to my UserInfo
UserInfo userInformation = new UserInfo (name, age)
In this case its easy because the request json body is static. I already now that i have a userInformation section and inside i have a name and age. To create a list with userInfo (to create multiple users at same time for example) i already implement things like this.
But now, for this specific case i have this json:
{
"nodes": {
"12131231231231241": {
"gToken": {
"token": "AABBCCDDEEFF99001122334455667788"
},
"objects": {
"WATER_CONTROL_1": "0"
}
},
"7682642342432423": {
"userAuthentication": {
"userEmail": "user#mail.com",
"userPassword": "userPassword"
},
"objects": {
"LIGHT_1_CONTROL": "1"
"LIGHT_3_CONTROL": "0"
}
}
}
}
So in this case i have some problems. In these example i put two items (12131231231231241,7682642342432423) but the user can send more (3,4,5,50,100). In the other hand inside nodes i have two sections (12131231231231241,7682642342432423) but this numbers are some ids that i use in my app and i never know that ids the user will put. In last example ( userInformation ) its simple because i create a userInformation section because i already know that the user always put this section, it is static. In these new json request i dont know, because i never now what value he put, i only know that is a string. The authentication method i dont have problems to create. But other problem that i expected to have is in objects section, because the user can put to a lot of objects and i never know what is the key (in userInformation i know that the keys are always the name and age for example and only exits these two keys, i these new case i dont know what is the keys and what are the number of pair of keys/values he put).
EDIT 3 -
I implement this code and i could almost produce all the structure I need. I'm using the gson same.
Nodes nodes;
public MonitorControlGetRequestArgs(String userEmail, String userPassword, Map <String,String> objects)
{
nodes = new Nodes(userEmail, userPassword, objects);
}
static class Nodes
{
AuthenticationMethod authenticationMethod;
Map <String,String> objects;
public Nodes(String userEmail, String userPassword, Map <String,String> objects)
{
authenticationMethod = new AuthenticationMethod(userEmail, userPassword);
this.objects = objects;
}
}
The result json:
{
"nodes": {
"authenticationMethod": {
"userAuthentication": {
"userEmail": "user#mail.com",
"userPassword": "userPassword"
}
},
"objects": {
"aa": "aaaaaaaaaaaaa",
"bbbbbbb": "bbbbb",
"ccdd": "ccddccdd"
}
}
}
Know i only need to add some struct to support this json:
{
"nodes": {
"7682642342432423": {
"authenticationMethod": {
"userAuthentication": {
"userEmail": "user#mail.com",
"userPassword": "userPassword"
}
},
"objects": {
"0": "Hammersmith & City",
"1": "Circle",
"dasd": "dasda"
}
}
}
}
Note: The objects is a map, so i can put the number of objects string/string that i want. Know i need to do something to support the previous json with the 7682642342432423, 12131231231231241, etc, etc..
EDIT 4 - final
Map <String, Obj> nodes;
public MonitorControlGetRequestArgs(Map <String, Obj> nodes)
{
this.nodes = nodes;
}
static class Obj
{
AuthenticationMethod authenticationMethod;
Map <String,String> objects;
public Obj(String userEmail, String userPassword, Map <String,String> objects)
{
authenticationMethod = new AuthenticationMethod(userEmail, userPassword);
this.objects = objects;
}
}
Json that arrive in my server (like i want)
{
"nodes": {
"12131231231231241": {
"authenticationMethod": {
"userAuthentication": {
"userEmail": "user#mail.com",
"userPassword": "userPassword"
}
},
"objects": {
"aa": "aaaaaaaaaaaaa",
"bbbbbbb": "bbbbb",
"ccdd": "ccddccdd"
}
},
"777777777777777": {
"authenticationMethod": {
"userAuthentication": {
"userEmail": "user#mail.com",
"userPassword": "userPassword"
}
},
"objects": {
"aa": "aaaaaaaaaaaaa",
"bbbbbbb": "bbbbb",
"ccdd": "ccddccdd"
}
}
}
}
Here is improved code from previous example that is more flexible and has better serialization mechanism :
public class ForTestApplication {
public static void main(String[] args) {
NodeArray jsonContainer = new NodeArray(
new Node("nodes", new NodeArray(
new Node("12131231231231241", new NodeArray(
new Node("gToken",
new Node("token", "AABBCCDDEEFF99001122334455667788")),
new Node("objects", new NodeArray(
new Node("WATER_CONTROL_1", "0"),
new Node("WATER_CONTROL_2", "1")
)))),
new Node("7682642342432423", new NodeArray(
new Node("userAuthentication", new NodeArray(
new Node("userEmail","user#mail.com"),
new Node("userPassword","userPassword")
)),
new Node("objects", new NodeArray(
new Node("WATER_CONTROL_1", "0"),
new Node("WATER_CONTROL_2", "1")
))
))
)));
System.out.println(jsonContainer.toJSONString());
}
}
class NodeArray {
private static final String NODE_TEMPLATE = "\"%s\":%s";
private static final Gson gson = new Gson();
private List<Node> nodes = new ArrayList<>();
public NodeArray(Node... nodes){
addNode(nodes);
}
public void addNode(Node... node){
nodes.addAll(Arrays.asList(node));
}
public String toJSONString() {
return nodes.stream()
.map(node -> String.format(NODE_TEMPLATE, node.getNodeName(), getNodeBodyAsJSON(node)))
.collect(Collectors.joining(",", "{", "}"));
}
private String getNodeBodyAsJSON(Node node) {
if (node.getNodeBody() instanceof NodeArray) {
return ((NodeArray) node.getNodeBody()).toJSONString();
}
return gson.toJson(node.getNodeBody());
}
}
class Node {
private final String nodeName;
private final Object nodeBody;
public Node(String nodeName, Object nodeBody) {
this.nodeName = nodeName;
this.nodeBody = nodeBody;
}
public String getNodeName() {
return nodeName;
}
public Object getNodeBody() {
return nodeBody;
}
}
The output of such application is :
{"nodes":{"12131231231231241":{"gToken":{"nodeName":"token","nodeBody":"AABBCCDDEEFF99001122334455667788"},"objects":{"WATER_CONTROL_1":"0","WATER_CONTROL_2":"1"}},"7682642342432423":{"userAuthentication":{"userEmail":"user#mail.com","userPassword":"userPassword"},"objects":{"WATER_CONTROL_1":"0","WATER_CONTROL_2":"1"}}}}
Pretty view is :
NOTICE : this example use constructors to build complex structures but I highly recommend to use builder pattern for such case. Code will be clearer and better.
Here is example of what you need using Gson. But if you would like to use something else, for example OrgJson then the code will be more clear and without String templates.
public class ForTestApplication {
private final static String nodeTemplate = "\"%s\":%s";
public static void main(String[] args) {
JsonData jsonData = new JsonData();
jsonData.addNode(new Node("user-1", new TestObject(62, "James", "Gosling")));
jsonData.addNode(new Node("user-2", new TestObject(53, "James", "Hetfield")));
System.out.println(jsonData.toJSONStirng());
}
static class JsonData {
List<Node> nodes = new ArrayList<>();
public void addNode(Node node){
nodes.add(node);
}
public String toJSONStirng() {
Gson gson = new Gson();
return nodes.stream()
.map(node -> String.format(nodeTemplate, node.getNodeName(), gson.toJson(node.getNodeBody())))
.collect(Collectors.joining(",", "{", "}"));
}
}
static class Node {
private final String nodeName;
private final Object nodeBody;
public Node(String nodeName, Object nodeBody) {
this.nodeName = nodeName;
this.nodeBody = nodeBody;
}
public String getNodeName() {
return nodeName;
}
public Object getNodeBody() {
return nodeBody;
}
}
static class TestObject {
private int age;
private String firstName;
private String lastName;
public TestObject(int age, String firstName, String lastName) {
this.age = age;
this.firstName = firstName;
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
}
Output :
{"user-1":{"age":62,"firstName":"James","lastName":"Gosling"},"user-2":{"age":53,"firstName":"James","lastName":"Hetfield"}}
Pretty view :

How do I nest a field within an Aggregation projection field in Spring Data Mongo

When written by hand, the $project step in my aggregation pipeline looks like:
{
"$project":{
"DRIVE":{
"componentSummary":{"manufacturer" : "$_id.DRIVE_manufacturer"},
"componentCount":"$_id.DRIVE_componentCount"
},
"hostnames":1,
"_id":0
}
}
I understand that I can use the ProjectionOperationBulder to create a single level of nesting (using builder.nested), to make something like, say:
{
"$project":{
"DRIVE":{
"manufacturer":"$_id.DRIVE_manufacturer"
},
"hostnames":1,
"_id":0
}
}
But I can't seem to figure out how to nest another level deep, as the Field interface only allows for a String name and a String target, rather than being able to define antother Field as the target.
Thanks!
For anyone else struggling with this -- Spring Data Mongo does not natively support multi level nesting as of this writing (stable version 1.9.5). However, as of 1.9.3, it does support custom AggregationExpressions that allow you to define the behavior yourself. Be aware that if you go down this route, you'll have to build the JSON for the query mostly by hand. My implementation is pretty quick and dirty but here it is for reference's sake.
protected class NestedField implements Field {
private String name;
private List<Field> fields;
public NestedField(String name, List<Field> fields) {
this.name = name;
this.fields = fields;
}
public List<Field> getFields() {
return fields;
}
#Override
public String getName() {
return name;
}
private String escapeSystemVariables(String fieldTarget) {
if (fieldTarget.startsWith("_id")) {
return StringUtils.prependIfMissing(fieldTarget, "$");
} else {
return fieldTarget;
}
}
private String encloseStringInQuotations(String quotable) {
return JSON.serialize(quotable);
}
private String buildSingleFieldTarget(Field field) {
if (field instanceof NestedField) {
return String.join(":", encloseStringInQuotations(field.getName()), field.getTarget());
}
return String.join(":", encloseStringInQuotations(field.getName()), encloseStringInQuotations(escapeSystemVariables(
field.getTarget())));
}
private String buildFieldTargetList(List<Field> fields) {
List<String> fieldStrings = new ArrayList<>();
fields.forEach(field -> {
fieldStrings.add(buildSingleFieldTarget(field));
});
return Joiner.on(",").skipNulls().join(fieldStrings);
}
#Override
public String getTarget() {
// TODO Auto-generated method stub
return String.format("{%s}", buildFieldTargetList(fields));
}
#Override
public boolean isAliased() {
return true;
}
}
protected class NestedProjection implements AggregationExpression {
private List<Field> projectedFields;
public NestedProjection(List<Field> projectedFields) {
this.projectedFields = projectedFields;
}#Override
public DBObject toDbObject(AggregationOperationContext context) {
DBObject projectionExpression = new BasicDBObject();
for(Field f : projectedFields) {
//this is necessary because if we just put f.getTarget(), spring-mongo will attempt to JSON-escape the string
DBObject target = (DBObject) com.mongodb.util.JSON.parse(f.getTarget());
projectionExpression.put(f.getName(), target);
}
return projectionExpression;
}
}

Convert object containing repeated fields to JSON

I have two table country and city in mysql dababase and i make a query to return records like that as List<myDTO> :
1,france,1,paris
1,france,2,marseille
1,france,3,lion
....
MyDTO
public class MyDTO {
public Integer idLvl1;
public String nameLvl1;
public Integer idLvl2;
public String nameLvl2;
public MyDTO(Integer idLvl1, String nameLvl1, Integer idLvl2, String nameLvl2) {
this.idNiv1 = idLvl1;
this.nomNiv1 = nameLvl1;
this.idNiv2 = idLvl2;
this.nomNiv2 = nameLvl2;
}
How can i convert it to json object to avoid the repeating country :
[
{"idNiv1" :1,"nameLvl1":"France","cities":[{"idNiv2":1,"nameLvl2":"paris"}]}
{"idNiv1" :1,"nameLvl1":"France","cities":[{"idNiv2":2,"nameLvl2":"marseille"}]}
{"idNiv1" :1,"nameLvl1":"France","cities":[{"idNiv2":3,"nameLvl2":"lion"}]}
....
]
to
[
{
"idNiv1" :1,
"nameLvl1":"France",
"cities":[
{ "idNiv2":1,"nameLvl2":"paris" } ,
{ "idNiv2":2,"nameLvl2":"marseille" } ,
{ "idNiv2":3,"nameLvl2":"lion" }
]
}
....
]
You can use Google's Gson in this case :
public String getJSONFromResultSet(ResultSet rs, String key) {
Map json = new HashMap();
List list = new ArrayList();
if (rs != null) {
try {
ResultSetMetaData mData = rs.getMetaData();
while (rs.next()) {
Map<String, Object> columns = new HashMap<String, Object>();
for (int columnIndex = 1; columnIndex <= mData.getColumnCount(); columnIndex++) {
if (rs.getString(mData.getColumnName(columnIndex)) != null) {
columns.put(mData.getColumnLabel(columnIndex),
rs.getString(mData.getColumnName(columnIndex)));
} else {
columns.put(mData.getColumnLabel(columnIndex), "");
}
}
list.add(columns);
}
} catch (SQLException e) {
e.printStackTrace();
}
json.put(key, list);
}
return new Gson().toJson(json);
}
Update:
You can call getJSONFromResultSet method like below :
Connection con = DBConnectionClass.myConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM Customer");
//as an example consider a table named Customer in your DB.
ResultSet rs = ps.executeQuery();
System.out.println(getJSONFromResultSet(rs, "customer"));
Create additional classes for country and city. Transform the flat structure to nested structure of country and cities as shown below:
public class Country {
Integer idLvl1;
String nameLvl1;
public Country(Integer idLvl1, String nameLvl1) {
}
List<City> cities;
}
public class City {
Integer idLvl2;
String nameLvl2;
public City(Integer idLvl2, String nameLvl2) {
}
}
public class MyDTOConverter {
public static Collection<Country> covert(List<MyDTO> dtos){
Map<Integer, Country> countries = new LinkedHashMap<Integer, Country>();
for (MyDTO myDTO : dtos) {
//First adding the country if it doesn't exist
if (!countries.containsKey(myDTO.idLvl1)){
countries.put(myDTO.idLvl1, new Country(myDTO.idLvl1, myDTO.nameLvl1));
}
//Adding city in the existing country.
countries.get(myDTO.idLvl1).cities.add(new City(myDTO.idLvl2, myDTO.nameLvl2));
}
return countries.values();
}
}
The final Collection of Country will result is the desired JSON.
You can write Wrapper DTO on top of Your MyDTO and then use any available json libraries like Google's Gson to convert to required JSON format.
Regards,
Sakumar

BeanWriter Disable outputting empty lists

I have the following bean:
public class ContractBean {
private List<String> listNd;
private String nd;
public List<String> getListNd() {
return listNd;
}
public void setListNd(final List<String> listNd) {
this.listNd = listNd;
}
public String getNd() {
return nd;
}
public void setNd(final String nd) {
this.nd= nd;
}
}
I use apache Betwixt to output XML from my bean.
final BeanWriter beanWriter = new BeanWriter(outputWriter);
beanWriter.getXMLIntrospector().getConfiguration().setAttributesForPrimitives(false);
beanWriter.getBindingConfiguration().setMapIDs(false);
beanWriter.enablePrettyPrint();
beanWriter.setWriteEmptyElements(false);
beanWriter.getBindingConfiguration().setObjectStringConverter(new CustomObjectStringConverter());
beanWriter.write(obj);
The listND attribute of my bean is null, but i still get:
<contract>
<listNd/>
<nd>22222</nd>
</contract>
How can I remove empty lists from the output XML ?

Categories

Resources