Spring Data Mongo: Create paged query for relation - pagination

I have an entity Feed that references a list of Articles. In my rest api, for any given Feed I want to have a /feed/{id}/articles endpoint that gives paged access to all the Articles in the Feed. I was thinking to create a query method in FeedRepository but have no clue how to return a page of Article instead of Feed from there. From the ArticleRepository, the problem is that Article has no reference to Feed.
Any ideas how to do what I need?
#Data
#Document
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class Feed {
#DBRef
private List<Article> articles;
}
#Data
#Document
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class Article {
#Id
private String id;
...
}

Related

Spring data MongoDB GeoSpatial Distance

I trying to find the distances along with the locations by using Spring Data Mongo GeoSpatial.
Following this https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo.geo-near
GeoResults<VenueWithDisField> = template.query(Venue.class)
.as(VenueWithDisField.class)
.near(NearQuery.near(new GeoJsonPoint(-73.99, 40.73), KILOMETERS))
.all();
I tried
#Data
#NoArgsConstructor
#AllArgsConstructor
public class RestaurantWithDisField {
private Restaurant restaurant;
private Number dis;
}
#Data
#AllArgsConstructor
#NoArgsConstructor
#Document(collection = "restaurants")
public class Restaurant {
#Id
private String id;
private String name;
#GeoSpatialIndexed(name = "location", type = GeoSpatialIndexType.GEO_2DSPHERE)
private GeoJsonPoint location;
}
public GeoResults<RestaurantWithDisField> findRestaurantsNear(GeoJsonPoint point, Distance distance) {
final NearQuery nearQuery = NearQuery.near(point)
.maxDistance(distance)
.spherical(true);
return mongoTemplate.query(Restaurant.class)
.as(RestaurantWithDisField.class)
.near(nearQuery)
.all();
}
But in the result I am getting the below. If I don't set the target type and just collect the domain type I get all the other values but the distance.
Restaurant - RestaurantWithDisField(restaurant=null, dis=0.12914248082237584
Restaurant - RestaurantWithDisField(restaurant=null, dis=0.19842138954997746)
Restaurant - RestaurantWithDisField(restaurant=null, dis=0.20019522190348576)
Can someone please help me why I am unable to fetch the domain type value or how should I?
Thank you
The mapping fails to resolve restaurant in RestaurantWithDisField because the values within the result Document do not match the target entities properties.
You might want to use inheritance instead of composition here and let RestaurantWithDisField extend Restaurant, provide your own converter or just use Restaurant and rely on GeoResults holding a list of GeoResult that already include the Distance along with the actual mapped domain type - pretty much the same, that you've be modelling with RestaurantWithDisField.
Spring Data Mongo repository can generate the right query for you if you name it correctly and put the data into your domain POJO. I was able to find examples here - blocking or here - reactive.
interface RestaurantRepository extends MongoRepository<Restaurant, String> {
Collection<GeoResult<Restaurant>> findByName(String name, Point location);
}
From what I see, the (Reactive)MongoTemplate uses a GeoNearResultDocumentCallback to wrap the restaurant in a GeoResult. You may want to take a look there.

How to map object references in mapstruct using JHipster?

Let's say that you create a JHipster app for a Blog with Posts using a JDL script like this and you want to have a BlogDTO that shows the Posts within it (and a BlogDTO that shows the Comments each Post has):
entity Blog {
creationDate Instant required
title String minlength(2) maxlength(100) required
}
entity Post {
creationDate Instant required
headline String minlength(2) maxlength(100) required
bodytext String minlength(2) maxlength(1000) required
image ImageBlob
}
entity Comment {
creationDate Instant required
commentText String minlength(2) maxlength(1000) required
}
// RELATIONSHIPS:
relationship OneToMany {
Blog to Post{blog required}
Post{comment} to Comment{post(headline) required}
}
// Set pagination options
paginate all with pagination
// DTOs for all
dto * with mapstruct
// Set service options to all except few
service all with serviceClass
// Filtering
filter *
Jhipster will create your Blog, Post and Comment entities with their DTOs and makes the assumption that you do not want to populate the Blog with the Posts or the Posts with the comments, so your BlogMapper will look like this:
#Mapper(componentModel = "spring", uses = {})
public interface BlogMapper extends EntityMapper<BlogDTO, Blog> {
#Mapping(target = "posts", ignore = true)
Blog toEntity(BlogDTO blogDTO);
default Blog fromId(Long id) {
if (id == null) {
return null;
}
Blog blog = new Blog();
blog.setId(id);
return blog;
}
}
with a BlogDTO like this:
public class BlogDTO implements Serializable {
private Long id;
#NotNull
private Instant creationDate;
#NotNull
#Size(min = 2, max = 100)
private String title;
//GETTERS, SETTERS, HASHCODE, EQUALS & TOSTRING
Can anybody help to modify the code so the BlogDTO will show the Posts (and the PostDTO will show the Comments). Thanks
PD: Because I changed the Annotation to include the PostMapper class
#Mapper(componentModel = "spring", uses = {PostMapper.class})
And the #Mapping(target = "posts", ignore = false) to FALSE but it does not work. The API example (Swagger) look fine, but then the PostDTO is null (even when the data is there).
Add a Set<PostDTO> posts; to your BlogDTO and a Set<CommentDTO> comments; to your PostDTO. Also add getters and setters for those fields in the DTO files. Then in your mappers, make sure that the BlogMapper uses PostMapper and that the PostMapper uses CommentMapper.
You may also need to configure the caching annotations on the posts field in Blog.java and the comments field in Post.java to fit your use-case. With NONSTRICT_READ_WRITE, there can be a delay in updating the cache, resulting in stale data returned by the API.

Need a new method in CatalogEndpoint: findAllProductsForCategory

I have REST API working, but I need a way to return all products within a certain category. Right now I'm using findSearchResultsByCategoryAndQuery by passing the category id and using a very generic query to get almost all the products in the category. What I really need is a method called findAllProductsForCategory which returns all products in the category.
I'm new to Broadleaf and REST API, can someone please guide me through how to extend CatalogEndpoint to get the functionality I need.
Althought broadleaf provides SQL injection protection (ExploitProtectionServiceImpl) I recommend you to use ProductDao.
Extend org.broadleafcommerce.core.web.api.endpoint.catalog.CatalogEndpoint or add in your implementation new method that utilize ProductDao
#Resource("blProductDao")
private ProductDao productDao;
#RequestMapping(value = "search/products-by-category/{categoryId}") //GET is by default
public List<Product> findSearchResultsByCategory(HttpServletRequest request, #PathVariable("categoryId") Long categoryId {
return productDao.readProductsByCategory(categoryId);
}
It's querying database with:
SELECT categoryProduct.product_id
FROM BLC_CATEGORY_PRODUCT_XREF categoryProduct
WHERE categoryProduct.category_id = :categoryId
ORDER BY COALESCE (categoryProduct.display_order,999999)
Or if you want to create your own dao
public class MyProductDaoImpl extends ProductDaoImpl implements MyProductDao {
public static final String QUERY = "SELECT categoryProduct.product_id " +
"FROM BLC_CATEGORY_PRODUCT_XREF categoryProduct " +
"WHERE categoryProduct.category_id = :categoryId";
#Override
public List<Product> meFindingProductsByCategory(String categoryId) {
Query query = em.createQuery(QUERY);
query.setParameter("categoryId", categoryId);
return query.getResultList();
}
}
You can choose if you are producing JSON or XML. Be sure that you have coresponding Product model for binding results

How to save inherited class using astyanax?

I am unable to save child class data with the persistence of parent class using astyanax in cassandra.
I created the child object with all necessary data, but when I try to store that object, only values from the parent class is stored, not from child object.
Here is the sample Code not real:
#Entity
class Shape{
#Id
private String id;
#Column
private String name;
}
#Entity
class square extends Shape{
#column
private int width;
}
now to store I am using EntityManager of astyanax.
square s=new square();
s.setName("sqaure");
s.setWidth(100);
s.setId("1234");
EntityManager em= //initialization code
em.put(s);
after doing this only "name" and "id" is stored into database. not width.
The EntityManager requires the type of the entity via the withEntityType() method. This type is used to build an EntityMapper via reflection which then determines the fields to serialize. There is nothing in the Entity persistence documentation or examples that says Astyanax supports polymorphism. This is not a bug, just a feature that doesn't exist. You will need a type-specific EntityManager for each subtype of your base class.

JPA and JSF Datatable Optimization

I need to display a large table with about 1300 roles at one time. (I know I should use a data scroll but my users want to see the whole table at one time.) The table displays 4 columns. Two of those columns are from the object but the other two are from referenced objects in the original object. I need to find the best/efficient way to do this. I currently have this working but when I reload the table it give an out of memory error. I think that it's caused by the large amount of redundant data in memory.
Create a view object that the repository will fill in only the needed fields.
Any other suggestions.
Here are the objects:
public class Database extends EntityObject {
private Long id;
private String name;
private String connectionString;
private String username;
private String password;
private String description;
// getter and setters omitted
}
public class Application extends EntityObject {
private Long id;
private String name;
private String fullName = "";
private String description;
private Database database;
private List<Role> roles = new ArrayList<Role>(0);
// getter and setters omitted
}
public class Role extends EntityObject {
private Long id;
private String name;
private String nameOnDatabase;
private Application application;
// getter and setters omitted
}
What I need displayed from the list of Roles is:
role.id, role.name, role.application.name, role.application.database.name
To optimize wisely, define what are you going to do with data, view or/and edit. Here are some common scenarios:
Retrieval using lazy fetch type.
Mark your roles in application with FetchType.LAZY annotation.
Retrieval using multiselect query. Create your custom class (like DTO) and populate it with data from the database using multiselect query. (Similar to VIEW mapped as Entity)
There are also other possibilities, such as Shared (L2) Entity Cache or Retrieval by Refresh.
See if you are using EntityManager correctly reading Am I supposed to call EntityManager.clear() often to avoid memory leaks?.

Resources