I am using Spring Boot and MongoDB for a personal project to create a movie and video game database. I have methods that retrieve the latest five entries of each category. When I was testing on a local Tomcat and MongoDB server, the methods work as expected. However, when I deploy to a tomcat server and connect to a MongoDB server, the methods that retrieve the latest five entries always return an empty array. here is the code:
Repository:
public interface MovieRepository extends MongoRepository<Movies, String>{
public List<Movies> findAllByOrderByTitleAsc(Pageable pageable);
#Query("{'title': {$regex: ?0, $options: 'i'}}")
public List<Movies> findByTitle(String title);
public List<Movies> findTop5ByCreatedAtLessThan(String currentDate);
public Movies findMovieById(String id);
public List<Movies> findByPlatformsIn(List<String> platforms);
}
Controller:
#RestController
#RequestMapping("/api")
public class MovieController {
#Autowired
private MovieRepository movieRepository;
#Autowired
private MapValidationErrorService mapValidationErrorService;
#Autowired
private CurrentDateService currentDateService;
#GetMapping("/movies")
public List<Movies> findAllMovies(#RequestParam(value="page", defaultValue="0")int page) {
return movieRepository.findAllByOrderByTitleAsc(PageRequest.of(page, 20));
}
#GetMapping("/movies/{movieId}")
public Movies findMovieById(#PathVariable("movieId") String movieId) {
return movieRepository.findMovieById(movieId);
}
#PostMapping("/movies")
public ResponseEntity<?> saveMovie(#Valid #RequestBody Movies movie, BindingResult result) {
ResponseEntity<?> errorMap = mapValidationErrorService.mapvalidationService(result);
if (errorMap != null) return errorMap;
movie.setId(null);
Movies newMovie = movieRepository.save(movie);
return new ResponseEntity<Movies>(newMovie, HttpStatus.OK);
}
#PutMapping("/movies")
public ResponseEntity<?> updateMovie(#Valid #RequestBody Movies movie, BindingResult result) {
ResponseEntity<?> errorMap = mapValidationErrorService.mapvalidationService(result);
if (errorMap != null) return errorMap;
Movies updatedMovie = movieRepository.save(movie);
return new ResponseEntity<Movies>(updatedMovie, HttpStatus.OK);
}
#DeleteMapping("/movies/{movieId}")
public void deleteMovieById(#PathVariable("movieId") String movieId) {
movieRepository.deleteById(movieId);
}
#GetMapping("/moviePlatforms")
public List<Movies> findMoviesByPlatforms(#RequestParam(value="platform") List<String>platforms) {
return movieRepository.findByPlatformsIn(platforms);
}
#GetMapping("/newFiveMovies")
public List<Movies> findTop5ByCreatedAt() {
String currentDate = currentDateService.getCurrentDate();
return movieRepository.findByCreatedAt(currentDate);
}
}
I have changed the find top 5 methods to use the #Query annotation, but it yields the same results. All the other methods in the controller and repository work as expected. I have tried using MongoDB on a Mac, and also on MongoDB Atlas. Any help is greatly appreciated.
I figured out that the date I was sending as a parameter was formatted wrong. The date was being stored as "M/d/yy h:mm a", but I was sending "M/dd/yyyy hh:mm a".
Related
Is there a way to query for multiple values of the same property with Spring DataREST JPA and querydsl? I am not sure what the format of the query URL should be and if I need extra customization in my bindings. I couldn't find anything in documentation. If I have a "student" table in my database with a "major" column with corresponding Student entity I would assume that querying for all students which have "math" and "science" majors would look like http://localhost:8080/students?major=math&major=science. However in this query only the first part is being taken and major=science is ignored
Below example customizes Querydsl web support to perform collection in operation. URI /students?major=sword&major=magic searches for students with major in ["sword", "magic"].
Entity and repository
public class Student {
private Long id;
private String name;
private String major;
}
public interface StudentRepos extends PagingAndSortingRepository<Student, Long>,
QuerydslPredicateExecutor<Student>,
QuerydslBinderCustomizer<QStudent> {
#Override
default void customize(QuerydslBindings bindings, QStudent root) {
bindings.bind(root.major)
.all((path, value) -> Optional.of(path.in(value)));
}
}
Test data
new Student("Arthur", "sword");
new Student("Merlin", "magic");
new Student("Lancelot", "lance");
Controller
#RestController
#RequestMapping("/students")
#RequiredArgsConstructor
public class StudentController {
private final StudentRepos studentRepos;
#GetMapping
ResponseEntity<List<Student>> getAll(Predicate predicate) {
Iterable<Student> students = studentRepos.findAll(predicate);
return ResponseEntity.ok(StreamSupport.stream(students.spliterator(), false)
.collect(Collectors.toList()));
}
}
Test case
#Test
#SneakyThrows
public void queryAll() {
mockMvc.perform(get("/students"))
.andExpect(status().isOk())
.andExpect(jsonPath("$").isArray())
.andExpect(jsonPath("$", hasSize(3)))
.andDo(print());
}
#Test
#SneakyThrows
void querySingleValue() {
mockMvc.perform(get("/students?major=sword"))
.andExpect(status().isOk())
.andExpect(jsonPath("$").isArray())
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0].name").value("Arthur"))
.andExpect(jsonPath("$[0].major").value("sword"))
.andDo(print());
}
#Test
#SneakyThrows
void queryMultiValue() {
mockMvc.perform(get("/students?major=sword&major=magic"))
.andExpect(status().isOk())
.andExpect(jsonPath("$").isArray())
.andExpect(jsonPath("$", hasSize(2)))
.andExpect(jsonPath("$[0].name").value("Arthur"))
.andExpect(jsonPath("$[0].major").value("sword"))
.andExpect(jsonPath("$[1].name").value("Merlin"))
.andExpect(jsonPath("$[1].major").value("magic"))
.andDo(print());
}
The full Spring Boot application is in Github
I am reading and learning Spring Boot data with MongoDB. I have about 10 records in my database in the following format:
{
"_id" : ObjectId("5910c7fed6df5322243c36cd"),
name: "car"
}
When I open the url:
http://localhost:8090/items
I get an exhaustive list of all items. However, I want to use the methods of MongoRepository such as findById, count etc. When I use them as such:
http://localhost:8090/items/count
http://localhost:8090/items/findById/5910c7fed6df5322243c36cd
http://localhost:8090/items/findById?id=5910c7fed6df5322243c36cd
I get a 404.
My setup is as so:
#SpringBootApplication
public class Application {
public static void main(String[] args) throws IOException {
SpringApplication.run(Application.class, args);
}
}
#Document
public class Item implements Serializable {
private static final long serialVersionUID = -4343106526681673638L;
#Id
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
#RepositoryRestResource(collectionResourceRel = "item", path = "items")
public interface ItemRepository<T, ID extends Serializable> extends MongoRepository<Item, String>, ItemRepositoryCustom {
}
What am I doing wrong? Do I need to implement the methods as defined by MongoRepository or will they be automatically implemented? I am lost and have been trying to figure this out for so long. I do not have any methods in my controller, its empty.
You have to declare the findById method in order for it to be exposed.
Item findById(String id);
Item findByName(String name);
Note that you don't need to implement the methods. SpringBoot will analyse the method name and provide the proper implementation
I had same issue,
After removing #Configuration,#ComponentScan everything worked fine.
HI i just want to know whether the XDCR replication is possible with spring data Couchbase. If possible how can i achieve that .please help .
My Code Sample
//configuration class
#Configuration
public class ApplicationConfig {
#Bean
public CouchbaseClient couchbaseClient() throws IOException {
return new CouchbaseClient(Arrays.asList(URI
.create("http://localhost:8091/pools")), "xxxw", "");
}
#Bean
public CouchbaseTemplate couchbaseTemplate() throws IOException {
return new CouchbaseTemplate(couchbaseClient());
}
}
#Document
public class Person {
#Field
String name;
#Id
String id;
public Person(final String personId, final String personname,
final int personIdAge, final JSONObject personData) {
this.id = personId;
this.name = personname;
this.age = personIdAge;
this.body = personData;
}
}
//main Test class
public class Test {
public static void main(String s[]) {
try {
ApplicationContext context = new AnnotationConfigApplicationContext(
ApplicationConfig.class);
CouchbaseTemplate template = context.getBean("couchbaseTemplate",
CouchbaseTemplate.class);
} catch (Exception e) {
e.printStackTrace();
}
}
How can i achieve repltcaion to elastic search index through spring data couchbase . with this sample classes ..??
Using elastic search in Couchbase is not dependent on what you client application looks like or whether or not it uses Spring. As long as you are storing data in Couchbase in JSON format things should work fine.
Setting up elastic search is more of an operations task than a development task. Take a look at the instructions at the link below and then run you application code as is. If you have configured everything properly then your data should end up in elastic search.
http://docs.couchbase.com/couchbase-elastic-search/
I am using the QueryDslPredicateExecutor from Spring Data JPA project, and I am facing the need to eager fetch a lazy relation. I know that I can use a native JPA-QL query in the Repository interface, or even used the JPAQLQuery from Query DSL, but I was intrigued if this is even possible in order to facilitate building queries for future needs.
I had a similar problem where I had to fetch join a Collection while using Predicates and QueryDslPredicateExecutor.
What I did was to create a custom repository implementation to add a method that allowed me to define the entities that should be fetched.
Don't be daunted by the amount of code in here, it's actually very simple and you will need to do very few changes to use it on your application
This is the interface of the custom repository
#NoRepositoryBean
public interface JoinFetchCapableRepository<T, ID extends Serializable> extends JpaRepository<T, ID>, QueryDslPredicateExecutor<T> {
Page<T> findAll(Predicate predicate, Pageable pageable, JoinDescriptor... joinDescriptors);
}
JoinDescriptor
public class JoinDescriptor {
public final EntityPath path;
public final JoinType type;
private JoinDescriptor(EntityPath path, JoinType type) {
this.path = path;
this.type = type;
}
public static JoinDescriptor innerJoin(EntityPath path) {
return new JoinDescriptor(path, JoinType.INNERJOIN);
}
public static JoinDescriptor join(EntityPath path) {
return new JoinDescriptor(path, JoinType.JOIN);
}
public static JoinDescriptor leftJoin(EntityPath path) {
return new JoinDescriptor(path, JoinType.LEFTJOIN);
}
public static JoinDescriptor rightJoin(EntityPath path) {
return new JoinDescriptor(path, JoinType.RIGHTJOIN);
}
public static JoinDescriptor fullJoin(EntityPath path) {
return new JoinDescriptor(path, JoinType.FULLJOIN);
}
}
Implementation of the custom repository
public class JoinFetchCapableRepositoryImpl <T, ID extends Serializable> extends QueryDslJpaRepository<T, ID> implements JoinFetchCapableRepository<T, ID> {
private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;
private final EntityPath<T> path;
private final PathBuilder<T> builder;
private final Querydsl querydsl;
public JoinFetchCapableRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
this(entityInformation, entityManager, DEFAULT_ENTITY_PATH_RESOLVER);
}
public JoinFetchCapableRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager, EntityPathResolver resolver) {
super(entityInformation, entityManager, resolver);
this.path = resolver.createPath(entityInformation.getJavaType());
this.builder = new PathBuilder<>(path.getType(), path.getMetadata());
this.querydsl = new Querydsl(entityManager, builder);
}
#Override
public Page<T> findAll(Predicate predicate, Pageable pageable, JoinDescriptor... joinDescriptors) {
JPQLQuery countQuery = createQuery(predicate);
JPQLQuery query = querydsl.applyPagination(pageable, createFetchQuery(predicate, joinDescriptors));
Long total = countQuery.count();
List<T> content = total > pageable.getOffset() ? query.list(path) : Collections.<T> emptyList();
return new PageImpl<>(content, pageable, total);
}
protected JPQLQuery createFetchQuery(Predicate predicate, JoinDescriptor... joinDescriptors) {
JPQLQuery query = querydsl.createQuery(path);
for(JoinDescriptor joinDescriptor: joinDescriptors)
join(joinDescriptor, query);
return query.where(predicate);
}
private JPQLQuery join(JoinDescriptor joinDescriptor, JPQLQuery query) {
switch(joinDescriptor.type) {
case DEFAULT:
throw new IllegalArgumentException("cross join not supported");
case INNERJOIN:
query.innerJoin(joinDescriptor.path);
break;
case JOIN:
query.join(joinDescriptor.path);
break;
case LEFTJOIN:
query.leftJoin(joinDescriptor.path);
break;
case RIGHTJOIN:
query.rightJoin(joinDescriptor.path);
break;
case FULLJOIN:
query.fullJoin(joinDescriptor.path);
break;
}
return query.fetch();
}
}
Factory to create the custom repositories, replacing the default QueryDslJpaRepository
public class JoinFetchCapableQueryDslJpaRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable>
extends JpaRepositoryFactoryBean<R, T, I> {
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new JoinFetchCapableQueryDslJpaRepositoryFactory(entityManager);
}
private static class JoinFetchCapableQueryDslJpaRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {
private EntityManager entityManager;
public JoinFetchCapableQueryDslJpaRepositoryFactory(EntityManager entityManager) {
super(entityManager);
this.entityManager = entityManager;
}
protected Object getTargetRepository(RepositoryMetadata metadata) {
return new JoinFetchCapableRepositoryImpl<>(getEntityInformation(metadata.getDomainType()), entityManager);
}
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return JoinFetchCapableRepository.class;
}
}
}
Last step is to change the jpa configuration so it uses this factory instead of the default one:
<jpa:repositories base-package="com.mycompany.repository"
entity-manager-factory-ref="entityManagerFactory"
factory-class="com.mycompany.utils.spring.data.JoinFetchCapableQueryDslJpaRepositoryFactoryBean" />
Then you can use it from your service layer like this:
public Page<ETicket> list(ETicketSearch eTicket, Pageable pageable) {
return eticketRepository.findAll(like(eTicket), pageable, JoinDescriptor.leftJoin(QETicket.eTicket.order));
}
By using JoinDescriptor you will be able to specify what you want to join based on your service needs.
I was able to do this thanks to the Murali's response here: Spring Data JPA and Querydsl to fetch subset of columns using bean/constructor projection Please take a look.
Spring data has introduced JPA Entity Graph support. Beware that is does not currently work with graphs that are traversed via EmbeddedIds.
I have a Library application which is already implemented in spring MVC.
I need to use ReST web services for the same application using spring 3.
I have a Controller class I want is to be as a RestFul webService
#Controller #SessionAttributes("category")
public class CategoryController {
private static final Log log = LogFactory.getLog(CategoryController.class);
#Autowired
private CategoryService categoryService;
#Autowired
private ItemService itemService;
#RequestMapping("/category/categoryList.htm")
public ModelAndView list(HttpServletRequest request,
HttpServletResponse response) throws Exception {
List<Category> list = categoryService.getAllMainCategories();
Map map = new HashMap();
map.put("categoryList", list);
map.put("category", new Category());
return new ModelAndView("categoryList", map);
}
#RequestMapping(method = RequestMethod.POST, value = "/category/save.htm")
public String save(HttpServletRequest request,
HttpServletResponse response, Category command) throws Exception {
log.debug("save method called" + command);
Category category = (Category) command;
System.out.println(category);
categoryService.saveCategory(category);
return "redirect:/category/categoryList.htm";
}
#RequestMapping("/category/edit.htm")
public String edit(#RequestParam String id, ModelMap model)
throws Exception {
log.debug("edit method called :" + id);
log.debug(Long.parseLong(id));
Category cat = categoryService.getCategory(Long.parseLong(id));
model.put("categoryList", categoryService.getAllMainCategories());
model.put("category", cat);
return "categoryList";
}
#RequestMapping("/category/delete.htm")
public String remove(#RequestParam String id, ModelMap model)
throws Exception {
log.debug("remove method called " + id);
categoryService.deleteCategory(Long.parseLong(id));
return "redirect:/category/categoryList.htm";
}
#InitBinder
protected void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Category.class,
new PropertyEditorSupport() {
#Override
public void setAsText(String text) {
setValue(categoryService.getCategory(Long.valueOf(text)));
}
});
}
}
it is CategoryController class which add delete or update a category
ItemService and CategoryService are data sources
Category is a domain object having properties like id,name,description etc..,
How do I write a REST web service for this?
There's a simple example showing how in Barebones Spring. Check it out.