How to search inside nested list object in spring boot data elastic-search - spring-data-elasticsearch

My contract model class
#Data
#Document(indexName = "contract",type = "contract")
public class Contract implements Serializable
{
#JsonProperty("contract_number")
#Id
#Parent(type = "p")
#Field(type = FieldType.Text,index =true)
private String contract_number;
private String startDate;
private String endDate;
private String supportTypeCode;
#Field(type = FieldType.Nested,searchAnalyzer = "true")
private List<Product> products;
My product class
#Data
public class Product implements Serializable
{
#Field(type = FieldType.Keyword)
private String baseNumber;
#Field(type = FieldType.Keyword)
private String rowId;
#Field(type = FieldType.Keyword)
private String effectiveDate;
}
Using spring data I,m trying to fetch data based on baseNumber which is present in product class.
But not able to get data.
I tried using below JPA Method but it is not working.
Optional<Contract> findByProducts_BaseNumber(String s)
I am quite confused about how to maintain a mapping between Contract and Product class.

That should be
findByProductsBaseNumber(String s);
or
findByProducts_BaseNumber(String s);
as explained in the documentation

For me below solution worked I'm using elastic 7.6 version java API.
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("products.baseNumber", baseNumber);
searchSourceBuilder.query(matchQueryBuilder);
searchSourceBuilder.from(0);
searchSourceBuilder.size(5);
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices(INDEX);
searchRequest.source(searchSourceBuilder);
SearchHits hits = null;
try
{
hits = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT).getHits();
final List<Contract> collect = Arrays.stream(hits.getHits()).map(
sourceAsMap -> objectMapper.convertValue(sourceAsMap.getSourceAsMap(), Contract.class)).collect(
Collectors.toList());
return collect.get(0);
}
catch (IOException e)
{
e.printStackTrace();
}

Related

How can I convert an Object to Json in a Rabbit reply?

I have two applications communicating with each other using rabbit.
I need to send (from app1) an object to a listener (in app2) and after some process (on listener) it answer me with another object, now I am receiving this error:
ClassNotFound
I am using this config for rabbit in both applications:
#Configuration
public class RabbitConfiguration {
public final static String EXCHANGE_NAME = "paymentExchange";
public final static String EVENT_ROUTING_KEY = "eventRoute";
public final static String PAYEMNT_ROUTING_KEY = "paymentRoute";
public final static String QUEUE_EVENT = EXCHANGE_NAME + "." + "event";
public final static String QUEUE_PAYMENT = EXCHANGE_NAME + "." + "payment";
public final static String QUEUE_CAPTURE = EXCHANGE_NAME + "." + "capture";
#Bean
public List<Declarable> ds() {
return queues(QUEUE_EVENT, QUEUE_PAYMENT);
}
#Autowired
private ConnectionFactory rabbitConnectionFactory;
#Bean
public AmqpAdmin amqpAdmin() {
return new RabbitAdmin(rabbitConnectionFactory);
}
#Bean
public DirectExchange exchange() {
return new DirectExchange(EXCHANGE_NAME);
}
#Bean
public RabbitTemplate rabbitTemplate() {
RabbitTemplate r = new RabbitTemplate(rabbitConnectionFactory);
r.setExchange(EXCHANGE_NAME);
r.setChannelTransacted(false);
r.setConnectionFactory(rabbitConnectionFactory);
r.setMessageConverter(jsonMessageConverter());
return r;
}
#Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
private List<Declarable> queues(String... nomes) {
List<Declarable> result = new ArrayList<>();
for (int i = 0; i < nomes.length; i++) {
result.add(newQueue(nomes[i]));
if (nomes[i].equals(QUEUE_EVENT))
result.add(makeBindingToQueue(nomes[i], EVENT_ROUTING_KEY));
else
result.add(makeBindingToQueue(nomes[i], PAYEMNT_ROUTING_KEY));
}
return result;
}
private static Binding makeBindingToQueue(String queueName, String route) {
return new Binding(queueName, DestinationType.QUEUE, EXCHANGE_NAME, route, null);
}
private static Queue newQueue(String nome) {
return new Queue(nome);
}
}
I send the message using this:
String response = (String) rabbitTemplate.convertSendAndReceive(RabbitConfiguration.EXCHANGE_NAME,
RabbitConfiguration.PAYEMNT_ROUTING_KEY, domainEvent);
And await for a response using a cast to the object.
This communication is between two different applications using the same rabbit server.
How can I solve this?
I expected rabbit convert the message to a json in the send operation and the same in the reply, so I've created the object to correspond to a json of reply.
Show, please, the configuration for the listener. You should be sure that ListenerContainer there is supplied with the Jackson2JsonMessageConverter as well to carry __TypeId__ header back with the reply.
Also see Spring AMQP JSON sample for some help.

Unable to get all task from JBPM 6.4

Is there a way to get all task and potential owners for each task from system?
I found that there are some method on task service but it returns only a part of the tasks and without potential owners.
You can always check records in table PEOPLEASSIGNMENTS_POTOWNERS and table TASK in database. Do you have access to database or you have to get such information from Workbench or rest api ?
This is my solution:
#Inject
TaskService taskService;
#Inject
#PersistenceUnit(unitName = "org.jbpm.domain")
private EntityManagerFactory emf;
EntityManager em = emf.createEntityManager();
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
final CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(TaskMinimal.class);
final Root taskRoot = criteriaQuery.from(TaskImpl.class);
final TypedQuery query = em.createQuery(criteriaQuery);
List<TaskMinimal> taskMinimals = query.getResultList();
List<Task> tasks = taskMinimals.stream()
.map(minimal -> taskService.getTaskById(minimal.getId()))
.collect(Collectors.toList());
public class TaskMinimal {
private long id;
public TaskMinimal(long id){
this.id = id;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
If you use KIE-Server, there is a REST API that provide all of these.Simply go to :8180/kie-server/docs for all details.

Spring Data Neo4j 4 - How to fetch parent of many to many entities correctly?

I have this problem when using findByIngredientId on pairing class I can't get ingredient (null) in the pairing result. But on debug mode the ingredient got fetched. What is the right way to fetch ingredient?
I tried using loadAllByProperty but its not working. It show the error below.
Is this the right way to fetch the parent node?
com.food.model.neo.Ingredient["pairings"]->java.util.HashSet[0]->com.food.model.neo.Pairing["first"]->com.food.model.neo.Ingredient["pairings"]->java.util.HashSet[0]->com.food.model.neo.Pairing["first"]->com.food.model.neo.Ingredient["pairings"]->java.util.HashSet[0]->com.food.model.neo.Pairing["first"]->com.food.model.neo.Ingredient["pairings"]->java.util.HashSet[0]->com.food.model.neo.Pairing["first"]->com.food.model.neo.Ingredient["pairings"]->java.util.HashSet[0]->com.food.model.neo.Pairing["first"]->com.food.model.neo.Ingredient["pairings"]->java.util.HashSet[0]->com.food.model.neo.Pairing["first"]->com.food.model.neo.Ingredient["pairings"]->java.util.HashSet[0]->com.food.model.neo.Pairing["first"]->com.food.model.neo.Ingredient["pairings"]->java.util.HashSet[0]->com.food.model.neo.Pairing["first"]->com.food.model.neo.Ingredient["pairings"]->java.util.HashSet[0]->com.food.model.neo.Pairing["first"]->com.food.model.neo.Ingredient["pairings"]->java.util.HashSet[0]->com.food.model.neo.Pairing["first"]->com.food.model.neo.Ingredient["pairings"]->java.util.HashSet[0]->com.food.model.neo.Pairing["first"]->com.food.model.neo.Ingredient["pairings"]->java.util.HashSet[0]->com.food.model.neo.Pairing["first"]->com.food.model.neo.Ingredient["pairings"]->java.util.HashSet[0]->com.food.model.neo.Pairing["first"]->com.food.model.neo.Ingredient["pairings"]->java.util.HashSet[0]->com.food.model.neo.Pairing["first"]-
And this is my classes:
#NodeEntity
public class Ingredient {
private Long id;
private String name;
#Relationship(type = "HAS_CATEGORY", direction = "OUTGOING")
private Category category;
#Relationship(type = "PAIRS_WITH", direction = "UNDIRECTED")
private Set<Pairing> pairings = new HashSet<>();
}
#NodeEntity
public class Category {
#GraphId
private Long id;
private String name;
}
#RelationshipEntity(type = "PAIRS_WITH")
public class Pairing {
Long id;
#StartNode
private Ingredient first;
#EndNode
private Ingredient second;
private String affinity;
}
This is my Controller.
#RequestMapping(value = "/foodStory", method = RequestMethod.GET)
public ModelAndView foodStory() {
ModelAndView model = new ModelAndView("home");
categoryRepository.deleteAll();
ingredientRepository.deleteAll();
pairingRepository.deleteAll();
//Set up the categories
Category meat = new Category("Meat");
Category veg = new Category("Vegetable");
categoryRepository.save(meat);
categoryRepository.save(veg);
//Set up two ingredients
Ingredient chicken = new Ingredient("Chicken");
chicken.setCategory(meat);
ingredientRepository.save(chicken);
Ingredient carrot = new Ingredient("Carrot");
carrot.setCategory(veg);
ingredientRepository.save(carrot);
//Pair them
Pairing pairing = new Pairing();
pairing.setFirst(chicken);
pairing.setSecond(carrot);
pairing.setAffinity("Delicious");
pairingRepository.save(pairing);
Ingredient carrotIngredient = session.loadByProperty(Ingredient.class, "name", "Carrot");
List<Pairing> pairingList = (List<Pairing>) session.loadAllByProperty(Pairing.class, "second", carrotIngredient);
//Check the data in pairingList and the result :
//expect to happens : pairings.first != null
//what happens : pairings.first = null
System.out.println("Done");
return model;
}
When I try to look at my pairingList data, pairings.first return null data.

Optimizing GraphClient Connection?

Below you will see my GraphOperations class (written in C# using Neo4jClient) that performs basic Neo4j graph operations. The GraphGetConnection() method connects to Neo4j and returns clientConnection and my CreateNode() method created a node and returns its node reference.
Now in that method you will see that Im going GraphOperations graphOp = new GraphOperations(); and then clientConnection= graphOp.GraphConnection();.
Is this the right way to do this?
Do I call a connection every time I want to perform an operation?
How do I optimize this code below? I want to create a method for each CRUD operation and want to find the best way to do this.
I hope the question is clear enough?
using Neo4jClient;
public class GraphOperations
{
GraphClient clientConnection;
public GraphClient GraphGetConnection()
{
clientConnection = new GraphClient(new Uri("http://localhost:7474/db/data"));
clientConnection.Connect();
return clientConnection;
}
public long GraphCreateNode(string type, string name, string customerName, string documentReference, int newVersionNumber)
{
Guid nodeGuid = Guid.NewGuid();
System.DateTime dateTime = System.DateTime.Now;
string timeStamp = String.Format("{0:dd MMMM yyyy HH:mm:ss}", dateTime);
GraphOperations graphOp = new GraphOperations();
clientConnection = graphOp.GraphGetConnection();
var createNode = clientConnection.Create(new VersionNode()
{
GUID = nodeGuid.ToString(),
Name = name,
Type = type,
DocumentReference = documentReference,
DateTimeCreated = timeStamp,
Version = newVersionNumber
});
return createNode.Id;
}
}
Well, you are already storing the GraphClient in the GraphOperations class, and as your GraphCreateNode method isn't static, you could just use that field, so your GraphCreateNode method becomes something like:
public long GraphCreateNode(string type, string name, string customerName, string documentReference, int newVersionNumber)
{
/* CODE */
this.GraphGetConnection(); //Don't care or need the return from GraphGetConnection
//From then on just:
clientConnection.DOSTUFF ....
/* CODE */
Personally, I would change a few things to make life a bit easier for yourself:
public class GraphOperations
{
private GraphClient clientConnection;
private void InitializeGraphClient()
{
if(this.clientConnection != null)
return;
this.clientConnection = new GraphClient(new Uri("http://localhost:7474/db/data"));
this.clientConnection.Connect();
}
public NodeReference CreateNode(/*parameters*/)
{
InitializeGraphClient();
Guid nodeGuid = Guid.NewGuid();
System.DateTime dateTime = System.DateTime.Now;
string timeStamp = String.Format("{0:dd MMMM yyyy HH:mm:ss}", dateTime);
var createNode = this.clientConnection.Create(
new VersionNode()
{
GUID = nodeGuid.ToString(),
Name = name,
Type = type,
DocumentReference = documentReference,
DateTimeCreated = timeStamp,
Version = newVersionNumber
});
return createNode.Id;
}
}
In each method (CRUD-wise) you'll call InitializeGraphClient and that will make sure the connection is there. The other way (and this might be preferable) is to stick that initialization into the constructor for GraphOperations:
public class GraphOperations
{
private readonly GraphClient clientConnection;
public GraphOperations()
{
this.clientConnection = new GraphClient(new Uri("http://localhost:7474/db/data"));
this.clientConnection.Connect();
}
public NodeReference CreateNode(/*parameters*/)
{
Guid nodeGuid = Guid.NewGuid();
System.DateTime dateTime = System.DateTime.Now;
string timeStamp = String.Format("{0:dd MMMM yyyy HH:mm:ss}", dateTime);
var createNode = this.clientConnection.Create(
new VersionNode()
{
GUID = nodeGuid.ToString(),
Name = name,
Type = type,
DocumentReference = documentReference,
DateTimeCreated = timeStamp,
Version = newVersionNumber
});
return createNode.Id;
}
}
and using that you should always know that the GraphClient instance will be there, which means your CRUD methods can focus on doing CRUD and not initializing the GraphClient. There is the potential with this that an Exception could be thrown from the constructor, but as to whether that is a bad thing or not is personal preference.

How to create a DAO for join tables?

I'm currently on learning on using Dao pattern in my project. I know, one Table is equivalent to one Dao, am I right? just like StudentDao, SubjectDao.
Each Dao performs CRUD operations in their associated tables, but my question is, how am I going to create a DAO for joined tables? lets say I have a query to join student and subject table, then how do I create a DAOfor that?
Should I place it to the StudentDao? or to SubjectDao? or there's a good practice in that kind of situation?
DAO - Data Access Object is Object that should only communicate with database. So if you want to JOIN two tables so you must have in your DTO Object StudentDTO reference on SubjectDTO.
public class StudentDTO {
private String name;
private String surname;
private String age;
private SubjectDTO subject;
// getters, setters
}
So, SubjectDTO
public class SubjectDTO {
private String name;
private int room;
// getters, setters
}
And DAO can look like this:
public StudentDAO {
private final String SELECT_QUERY = "SELECT * FROM Student S JOIN Subject Sb ON (S.id = Sb.id)"
public ArrayList<StudentDTO> getData() {
ArrayList<StudentDTO> data = null;
StudentDTO member = null;
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = OracleDAOFactory.getConnection();
ps = con.prepareStatement(SELECT_QUERY);
rs = ps.executeQuery();
while (rs.next()) {
member = new StudentDTO();
member.setName(rs.getString(1));
...
data.add(member);
}
return data;
}
catch (SQLException ex) {
// body
}
finally {
if (con != null) {
con.close();
}
}
}
}
I recommend to you check some tutorials.
Regards

Resources