I'm just getting started with elasticsearch with spring which is both technologies which are completely new to me. I have uploaded data to an elasticseach index with logstash and I can search it successfully using kebana. However when I try to return from an index to a webpage using spring it only returns empty json-objects, but the right amount of empty objects. Did I upload the data incorrectly or is something wrong with my code? I don't understand why this is happening and would appreciate any help I can get. You can find some code below.
Code for type:
#Document(indexName="usmgbg_index", type="usmgbg_type")
public class Usmgbg {
#Id
private String ID;
private String Source, Name, Profession, Country, FileName, LastModified, OwnerID;
}
Repository:
#Repository
public interface UsmgbgRepository extends ElasticsearchRepository<Usmgbg, String>{}
Controller:
#RestController
public class UsmgbgController {
#Autowired
private UsmgbgRepository repository;
#GetMapping("usmgbg/findall")
public List<Usmgbg> findAllCustomers() {
List<Usmgbg> items = new ArrayList<>();
repository.findAll().forEach(items::add);
return items;
}
}
The output I'm getting from findAllCustomers looks like:
[{},{},{},{},....]
I realize this is an old question but I had the same issue (maybe for a different reason) and I solved it by adding getters and setters in the model.
Iterable is returned from findAll().
If you want to get list you should get content first.
Change
#Repository
public interface UsmgbgRepository extends
ElasticsearchRepository<Usmgbg, String>{
Page<Usmgbg> findAll();
}
And then
repository.findAll().getContent().forEach(items::add);
Or fix your code to iterate over the results.
Another solution is to use search method in ElasticsearchRepository using QueryBuilders API.
Iterable<Usmgbg>=
repository.search(QueryBuilders.matchAllQuery);
Adding my experience
spring-data requires getters to follow the POJO naming, i.e: getSomething()
so it did not work (spring-data did not send any fields to ElasticSearch when saving the #Document, resulting in an empty _source in ES) when having Lombok #Accessors(fluent = true), as it removes the get prefix on getters ...
Related
Hi I have implemented a mock solution to my problem and I'm pretty sure something better already exist.
Here's that I want to achieve :
I have created a point to load categories with or without subCategories
/api/categories/1?fields=subCategories
returns
{
"id":"1",
"name":"test",
"subCategories":[{
"id":"1",
"name":"test123"
}]
}
/api/categories/1
returns
{
"id":"1",
"name":"test"
}
My entities
#Entity
class Category{
#Id
private String id;
private String name;
private Set<SubCategory> subCategories;
}
#Entity
class SubCategory{
#Id
private String id;
private String name;
}
I have removed services since this is not the point.
I've created CategoryDTO and SubCategoryDTO classes with the same fields as Category and SubCategory
The converter
class CategoryDTOConverter{
CategoryDTO convert(Category category,String fields){
CategoryDTO dto=new CategoryDTO();
dto.setName(category.getName());
if(StringUtils.isNotBlank(fields) && fields.contains("subCategories"){
category.getSubCategories().forEach(s->{
dto.getSubcategories().add(SubCategoryDTOConverter.convert(s));
}
}
}
}
I used com.cosium.spring.data.jpa.entity.graph.repository to create an EntityGraph from a list of attribute path
#Repository
interface CategoryRepository extends EntityGraphJpaRepository<Category, String>{
Optional<T> findById(String id,EntityGraph entityGraph);
}
Controller
#RestController
#CrossOrigin
#RequestMapping("/categories")
public class CategoryController {
#GetMapping(value = "/{id}")
public ResponseEntity<CategoryDTO> get(#PathVariable("id") String id, #RequestParam(value="fields",required=false) String fields ) throws Exception {
Optional<Category> categOpt=repository.findById(id,fields!=null?EntityGraphUtils.fromAttributePaths(fields):null);
if(categOpt.isEmpty())
throws new NotFoundException();
return ResponseEntity.ok(categoryDTOConverter.convert(categOpt.get(),fields);
}
}
This is a simple example to illustrate what I need to do
I don't want to load fields that clients doesn't want to use
How could I do this in a better way ?
Take a look at GraphQL since it is a perfect match for your use case. With GraphQL it is the client that decides which attributes it wants to receive by providing in the POST request body exactly which attributes are needed to be included in the response. This is way more manageable than trying to handle all this on your own.
Spring Boot recently added its own Spring GraphQL library, so it is quite simple to integrate it in your Spring Boot app.
My Repository Method Query cannot parse a property name that comes after the OrderBy, but it can if it follows the findBy or findAllBy. The attribute in my entity that is giving me issues is zIndex
Entity Class
#Entity
public class DisplayLayer
{
#Id
#Column(name="DISPLAY_LAYER_ID")
private Long id;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name="DISPLAY_CONTAINER_ID")
private DisplayContainer displayContainer;
#Column(name="NAME")
private String name;
#Column(name="Z_INDEX")
private Long zIndex;
#Column(name="DESCRIPTION")
private String description;
// Getters & Setters
}
Repository Class
public interface DisplayLayerRepository extends BaseRepository<DisplayLayer, Long>
{
// This one method query works just fine
public List<DisplayLayer> findByZIndex(Long pZIndex);
// These two throw the same error:
// Unable to locate Attribute with the the given name [ZIndex]
//
// public List<DisplayLayer> findAllByOrderByZIndexAsc();
// public List<DisplayLayer> findByDisplayContainerIdOrderByZIndexAsc(Long pDisplayLayerId);
}
So in my first method query, when OrderBy is not used, it correctly parses it as [zIndex], but when it follows the OrderBy for some reason it capitalizes the z: [ZIndex].
Is this a known issue, or am I doing something wrong?
EDIT
What makes me think there might be a bug with the parser is that if I update zIndex to IndexZ in my entity and then change my query methods from OrderByZIndex to OrderByIndexZ everything works.
This solution is not ideal though as the database table is Z_INDEX and that has a specific meaning when talking about layering of graphics.
Yes there is a bug but there is a simple workaround, please try :
displayLayerRepository.findAll(Sort.by(Sort.Order.desc("zIndex").ignoreCase()));
I suppose DisplayLayerRepository extends JpaRepository.
It's similar when you use parameters in your findBy method. Define in your repository empty method :
public List<DisplayLayer> findByDisplayContainerId(Long pDisplayLayerId, Sort sort);
Then you can call it by :
displayLayerRepository.findByDisplayContainerId(1L, Sort.by(Sort.Order.desc("zIndex").ignoreCase()));
You can use JpaSort in query. As in your case, it looks something like this:
Sort sort = JpaSort.unsafe(Sort.Direction.ASC, "zIndex");
List<DisplayLayer> zIndexes = displayLayerRepository.findByZIndex(pZIndex, sort);
and your query in Repository will look like this:
public List<DisplayLayer> findByZIndex(Long pZIndex, Sort sort);
I have a model looking something like this:
#Data
public abstract class InputFormGroup
{
String id;
String name;
String text;
String type;
}
#Data
public class SimpleInputFormGroup extends InputFormGroup
{
InputControl inputControl;
InputFormAnswerRow answerRow;
}
#Data
public class InputFormPage
{
String id;
String name;
String title;
List<InputFormGroup> inputFormGroups = new LinkedList<>();
}
In effect I have a larger structure that in it has InputFormPages that has one or more InputFormGroups that can be of type SimpleInputFormGroup (and also other types that I have not included in this example).
Im using MongoRepository to persist them and everything looks very nice and I can query the changes on the Entity object and it all looks good.
The only time I have an issue is when I try to query with a path. In this example "..../inputFormPages/0/inputFormGroups/0/answerRow/answers/0".
Then I get the exception because the framework finds a list of InputFormGroup but then when it looks for answerRow in the abstract InputFormGroup base class it does naturally not find it. Is there some way to configure the model so the framework also looks in the derived classes for, in this case, the answerRow parameter? Of is it as simple as the framework doesn't support polymorphism in this way?
The error I got:
"JaversException PROPERTY_NOT_FOUND: Property 'answerRow' not found in class 'com.replior.ebrmockupbackend.model.InputFormGroup'. If the name is correct - check annotations. Properties with #DiffIgnore or #Transient are not visible for JaVers."
And the Query:
JqlQuery query = QueryBuilder.byValueObjectId(batch1.getId(),Batch.class,"inputForm/inputFormSteps/2/inputFormPages/0/inputFormGroups/0/answerRow/answers/0").withChangedProperty("value").build();
List<Change> changes = javers.findChanges(query);
And the version:
<dependency>
<groupId>org.javers</groupId>
<artifactId>javers-spring-boot-starter-mongo</artifactId>
<version>3.10.2</version>
</dependency>
Appreciate any help I can get.
Link to project that exemplifies the issue:
Github project
This issue is fixed in JaVers 3.11.3
I am using hateoas for implementing links in my repositories.So my Customer Class extends ResourceSupport which has private final List<Link> links; and in constructor
public ResourceSupport() {
this.links = new ArrayList<Link>();
}
So when I am saving customer entity using Mongo template mongoTemplate.save(customer);
So when I see the documents in Mongo db it shows
{
_id:"objectid(57vsdsjdsk),
firstName:"Yamini",
lastName:"Tyagi"
links as empty Array List(initialized in constructor)
}
So how would I avoid links to be persisted in Mongo database?
Please help on this?
I have overloaded the get method of that property in my child class and marked that as #Transient
Using the #Transient annotation that particular property will not save in Database. Hope this will help
#Override
#Transient
public java.util.List<org.springframework.hateoas.Link> getLinks() {
return super.getLinks();
}
I got a problem with simple Spring Data issue. Let's assume we got two entities.
public class Request {
// all normal stuff
#ManyToOne
private Document doc;
}
public class Document {
private Long id;
private String name;
}
Simple relation. My question is - is it possible to retrieve Request entities using Spring Data Method-DSL and sorting by Document? So what I want to achieve is to create repository method like:
public List<Request> findAllOrderByDoc()
or similar:
public List<Request> findAllOrderByDocId()
Unfortunately when I try that I am given error message saying that there is no Doc field or it cannot be mapped to long. I assume it is possible to be done using QueryDSL and predicates but I am wondering if this pretty obvious and simple thing can be done by plain Spring Data?
Yes, sure.
you need to provide the direction:
public List<Request> findAllOrderByDocAsc()
public List<Request> findAllOrderByDocDesc()