Getting an error with mapping when using MongoRepository findById - java

When I try to use the findById method from MongoRepository with a string passed in, I get an error with the mapper which leads to no results being returned, even though such exists.
Here is my project's structure and files:
Entity Post.java
#Document("posts")
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Post {
#Id
private String Id;
private Integer userId;
private String content;
private Integer likes;
private Integer dislikes;
}
Repository PostRepository.java
public interface PostRepository extends MongoRepository<Post, String> {
}
Service PostService.java
#Service
public class PostService {
#Autowired
private PostRepository repository;
public List<Post> getPosts() {
return repository.findAll();
}
public Post getPostById(String id) {
return repository.findById(id).orElse(null);
}
public Post savePost(Post post) {
return repository.save(post);
}
public void deletePostById(String id) {
repository.deleteById(id);
}
}
Controller PostController.java
#RestController
#RequestMapping("/posts")
public class PostController {
#Autowired
private PostService service;
#Autowired
private StreamBridge streamBridge;
#GetMapping("")
public List<Post> getPosts() {
return service.getPosts();
}
#GetMapping("/{postId}")
public Post getPostById(#PathVariable String postId) {
return service.getPostById(postId);
}
#PostMapping("/createPost")
public Post createPost(#RequestBody Post post) {
streamBridge.send("postCreated-out-0", post.getUserId());
return service.savePost(post);
}
#DeleteMapping("/{postId}")
public void deletePostById(#PathVariable String postId) {
service.deletePostById(postId);
}
}
When I try running either a GET such as localhost:9192/posts/62a76719145e644e5b640327 or a DELETE localhost:9192/posts/62a76719145e644e5b640327, where 62a76719145e644e5b640327 is a correct id associated with a entry in the document in MongoDB I get this error in the console:
[nio-9192-exec-2] o.s.d.mongodb.core.convert.QueryMapper : Could not map 'Post.id'. Maybe a fragment in 'String' is considered a simple type. Mapper continues with id.
I also tried writing a custom query using the #Query annotation that overwrites the default findById as such:
#Override
#Query("{ 'id' : ?0}")
Optional<Post> findById(String s);
And I still get the same error. I am using spring-boot-starter-data-mongodb version 2.7.0 and I am running MongoDB locally.
EDIT: Forgot to mention that the same thing happens when using the deleteById method

i think the problem is in the identifier u named it with capital I
replace Id in posts document with id ?
give it a try... it will work

Related

Spring Data Couchbase: Count() nor findAll() does not work but findBy() works

I am currently setting up a Rest API server using Spring Boot (v2.5.5), Spring Data Couchbase (v4.2.5) and Couchbase (v6.6.1).
I get a really strange behavior when requesting
count() -> 0
findAll() -> []
Whereas
findById() is returning a result.
My entity:
{"mkey": { "keyContent": "AA", "mkeyStatus": "L" }, "sequences": [ { "direction": "B", "loc1Value": "NCE", "loc2Value": "NYC" } ] }
#Document #Data #AllArgsConstructor #NoArgsConstructor #EqualsAndHashCode public class AirlineProfile {
#Id private String id;
#Field private MKey mkey;
#Field private List<Sequence> sequences;
#EqualsAndHashCode #AllArgsConstructor #NoArgsConstructor #Data static class MKey {
#Field private String keyContent;
#Field private String mkeyStatus;
}
#EqualsAndHashCode #AllArgsConstructor #NoArgsConstructor #Data static class Sequence {
#Field private String loc1Value;
#Field private String loc2Value;
#Field private String direction;
}
}
My repository is extending the CrudRepository.
public interface AirlineProfileRepository extends CrudRepository<AirlineProfile, String> {}
While my Service is the following:
#Service #Qualifier("AirlineProfileServiceImpl") public class AirlineProfileServiceImpl
implements AirlineProfileService {
#Autowired private AirlineProfileRepository airlineProfileRepository;
#Override
public long count() {
return airlineProfileRepository.count();
}
#Override
public List<AirlineProfile> findAll() {
List<AirlineProfile> airlineProfiles = new ArrayList<>();
for (AirlineProfile airlineProfile : airlineProfileRepository.findAll()) {
airlineProfiles.add(airlineProfile);
}
return airlineProfiles;
}
#Override public AirlineProfile findById(String id) {
return airlineProfileRepository.findById(id).orElse(null);
}
}
And my controller the following:
#RestController #RequestMapping("/api") public class AirlineProfileController {
#Autowired AirlineProfileService airlineProfileService;
#GetMapping("/airlineprofile/count") public long count() {
System.out.println("Count");
return airlineProfileService.count();
}
#GetMapping("/airlineprofile/all") public List<AirlineProfile> getAllAirlineProfiles() {
System.out.println("Get all AirlineProfile");
return airlineProfileService.findAll();
}
#GetMapping("/airlineprofile/id={id}") public AirlineProfile getAirlineProfileById(#PathVariable String id) {
System.out.println("Get AirlineProfile for id = " + id);
return airlineProfileService.findById(id);
}
}
I do not know if I missed something at Server or Couchbase side ... :(
Thank you for your help!
Ok, found that:
public interface AirlineProfileRepository extends CrudRepository<AirlineProfile, String> {
#Query("#{#n1ql.selectEntity}")
List<AirlineProfile> findAll();
}
Is working ...
So, I am questioning myself about the usability of findAll() ...

Quarkus: #Valid doesn’t work with PanacheMongo

I have a problem with validation of my bean.
I'm using Quarkus with MongoDB and when I try to run a create REST API, with #Valid annotation before request bean, I expect an exception if I want to create a document with null field (obviously I use #NotNull in entity), but document is created without field.
Here is my code:
Car.java:
#MongoEntity(collection="cars")
public class Car extends PanacheMongoEntityBase {
#BsonId
private long id;
#NotNull
private String carName;
#NotNull
#Size(min = 1, max = 3)
private String code;
// get and set
}
CarResource.java:
#Path("/cars")
#Consumes("application/json")
#Produces("application/json")
public class CarResource {
#GET
public List<Car> list() {
return Car.listAll();
}
#GET
#Path("/{id}")
public Car get(long id) {
return Car.findById(id);
}
#POST
public Response create(#Valid Car car) {
car.persist();
return Response.status(201).build();
}
I have same problem with #Size annotation, because I can create a code field with more characters than 3.
UPDATE
Validation works with quarkus-hibernate-validator.
Now, I have to find a solution for unique field.
And besides from the main question: is there an annotation like #Indexed(unique = true)? I want an unique field for my app.
You need to use #Validated annotation on CarResource Class as shown below.
#Path("/cars")
#Consumes("application/json")
#Produces("application/json")
#Validated
public class CarResource {
#GET
public List<Car> list() {
return Car.listAll();
}
#GET
#Path("/{id}")
public Car get(long id) {
return Car.findById(id);
}
#POST
public Response create(#Valid Car car) {
car.persist();
return Response.status(201).build();
}
}

Save new data with Spring JPA - Angular 8

I'm learning Spring with JPA. I created a local DB with MySQL storing "Users", a web service with Spring and a front with angular.
I fed some data to my DB, and managed to display it with Angular. But the Post request coming from the Angular form does not seems to work. The form works well and provide an Object.
User model:
#Entity
#Table(name = "utilisateur")
public class Utilisateur {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String firstname;
private String lastname;
private int age;
DAOuser :
#Repository
public interface DAOutilisateur extends JpaRepository<Utilisateur, Integer> {
}
UserController :
#RestController
#CrossOrigin(origins = "http://localhost:4200")
public class UtilisateurController {
DAOutilisateur utilisateurDAO;
#Autowired
public UtilisateurController(final DAOutilisateur utilisateurDAO) {
this.utilisateurDAO = utilisateurDAO;
}
#GetMapping({"/listeUtilisateur"})
public List<Utilisateur> listUtilisateur(){
System.out.println("Liste des utilisateurs");
return utilisateurDAO.findAll();
}
#PostMapping("/listeUtilisateur")
void addUser(#RequestBody Utilisateur user) {
System.out.println("ECHO");
utilisateurDAO.save(user);
}
}
TypeScript Fonction used in Angular to access the Post URL, User is an Object created via an Form:
public saveUserSpring(user: UserSpring) {
return this.http.post<UserSpring>(this.userUrl, user);
}
Thank you for your Help !
Bertrand
Solved
As Rohit Kavathekar mentioned above, I didn't subscribed to the .post method in my angular project, which return an Observable and required to be subscribed.
Thank you.

How to delete record in MongoDB using Spring Data

I want to delete an record based on Id in Spring.
but in database id value is object
EX:-
id: Object(34562341112313)
How to delete this record in Spring?
You do like this:
public void deleteRecord() {
MongoOperations mongoOperation = (MongoOperations) ctx.getBean("mongoTemplate");
Query searchQuery = new Query(Criteria.where("id").is(34562341112313));
mongoOperation.remove(searchQuery, Your_entity_class.class);
logger.info("Delete success");
}
This is my realistic example:
/**
* Delete by condition(s).
*/
public void deleteJob() {
MongoOperations mongoOperation = (MongoOperations) ctx.getBean("mongoTemplate");
Query searchQuery = new Query(Criteria.where("company").is("DCV"));
mongoOperation.remove(searchQuery, Job.class);
logger.info("Đã xóa các công việc đăng bởi DCV.");
}
Source: https://github.com/SmartJobVN/MongoDB_SpringDataMongo/blob/master/src/main/java/vn/smartJob/jobs/MongoSpringJavaConfigApplication.java#L132
Reference: http://docs.spring.io/spring-data/mongodb/docs/current/reference/html/
You should delete it like this:
#Repository
public class AppDaoClass{
#Autowired
MongoTemplate mongoTemplate;
#Override
public void deleteSomething(String somethingId) {
mongoTemplate.remove(Query.query(Criteria.where("somethingId").is(somethingId)), Ticket.class);
}
}
The first "somethingId" is the name you gave it in your model, and the second somethingId is for the Parametar you are giving in you method.
And your Domain Model:
#Document
public class Model {
#Id
private String somethingId;
private String someName;
private String someOtherName;
}
Be sure to user proper annotations for your classes #Document and #Repository. And add an #Id annotation to your ID field.
Hope this helps.
This is the way you can delete records in spring data mongoDB using MongoTemplate
WriteResult writeResult=mongoTemplate.remove(query,"collection_name");
OR
WriteResult writeResult=mongoTemplate.remove(query,EntityClassName.class);
You can also use repository Pattern
#Document(collection = "user")
public class User {
#Id
private String id;
private String username;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
#Repository
public interface UserRepository extend MongoRepository<User, String>{
public void delete(String id);
public void delete(User user);
public void deleteByUsername(String username);
}
you can use these method anywhere to delete records also u can write your custom methods
#Query(value = "{'_id' : ?0}", delete = true)
void deleteById(String id);

Spring-Boot Data MongoDB - How to getting a specific nested object for a super specific object

I have the following data model, and I want to get a specific object in the sub list objects, I know it's possible to get the entire list and go through each object and compare with what the search id, but I wonder if it is possible use MongoRepository to do this.
#Document
public class Host {
#Id
private String id;
#NotNull
private String name;
#DBRef
private List<Vouchers> listVoucher;
public Host() {
}
//Getters and Setters
}
And..
#Document
public class Vouchers {
#Id
private String id;
#NotNull
private int codeId;
public Vouchers() {
}
//Getters and Setters
}
The Repository Class:
public interface HostRepository extends MongoRepository<Host, String> {
List<Host> findAll();
Host findById(String id);
Host findByName(String name);
//How to build the correct query ??????????
List<Vouchers> findVouchersAll();
Vouchers findByVouchersById(String hostId, String voucherId);
}
The Controller Class:
#RestController
#RequestMapping(value = "api/v1/host")
public class VoucherController {
#Inject
HostRepository hostRepository;
#RequestMapping(value = "/{hostId}/voucher",method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public List<Vouchers> list() {
return hostRepository.findVouchersAll();
}
#RequestMapping(value = "/{hostId}/voucher/{voucherId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public Vouchers getOneVoucher(#PathVariable String hostId, #PathVariable String voucherId) {
Vouchers voucher = hostRepository.findByVouchersById(hostId, voucherId);
if (voucher != null) {
return voucher;
} else {
throw new VoucherNotFoundException(String.format("There is no voucher with id=%s", voucherId));
}
}
}
Thanks in Advance!
I think there is a way to do this although I have not tried this myself but maybe I can shed some light in how I would do it.
Firstly, I would rather use the more flexible way of querying mongodb by using MongoTemplate. MongoTemplate is already included in the Spring Boot Mongodb data library and it looks like you are already using the library so it is not an additional library that you will have to use. In Spring there is a way to #Autowired your MongoTemplate up so it is quick and easy to get the object for completing this task.
With mongoTemplate, you would do something like this:
Query query = new Query();
query.addCriteria(Criteria.where("listVouchers.id").is("1234"));
List<Host> host = mongoTemplate.find(query, Host.class);
Please see docs here: https://docs.mongodb.org/manual/tutorial/query-documents/

Categories