Couchbase document id generation - spring-boot

I have an Springboot application integrated with couchbase 6.0.
I have read that if a key is annotated with #Id then it will saved as an document id and will not be a part of the json.
Then i have used #Id and #Field together on the key but still that field is not appearing on json document.
Can somebody help me out on the following:
1: How to make same key as document id and keep that a part of json also.
2: If a field is declared with #Id, it is created as document id and does
not appear on document, but when i do a get request same key appear on
the response.
I have also tried, click here https://docs.spring.io/spring-data/couchbase/docs/current/reference/html/#couchbase.autokeygeneration.usingattributes
My entity is:
#Id #GeneratedValue(strategy = GenerationStrategy.USE_ATTRIBUTES,delimiter="::")
private String id;
#IdAttribute
private String userid;
#Field
private String fname;
#Field
private String lname;
Post method body:
{
"id": "888",
"userid":"user1",
"fname": "xyz",
"lname": "abc"
}
In Couchbase server, it is saving this document as
It is creating document id as 888 only, it is supposed to generate documnet id as 888::user1
I have tested this many times but the result is same.

Looks like you're looking for Key generation using attributes:
It is a common practice to generate keys using a combination of the
document attributes. Key generation using attributes concatenates all
the attribute values annotated with IdAttribute, based on the ordering
provided similar to prefixes and suffixes.
So, for example you can do:
#Document
public class User {
#Id #GeneratedValue(strategy = USE_ATTRIBUTES)
private String id;
#IdAttribute
private String userid;
...
}
According to the example above you will get as a result a Document with the id = userId and also the field userId in the json.
UPDATE AS PER QUESTION EDIT
You may have to include a new filed in your entity, let's say postId and change the naming of the id field in your post method body by postId, something like:
Entity:
#Id #GeneratedValue(strategy = GenerationStrategy.USE_ATTRIBUTES,delimiter="::")
private String id;
#IdAttribute(order = 0)
private String postId;
#IdAttribute(order = 1)
private String userid;
#Field
private String fname;
#Field
private String lname;
Post method body:
{
"postId": "888",
"userid":"user1",
"fname": "xyz",
"lname": "abc"
}

Related

Advantage of assigning the returned savedEntity in Spring Data

I see in most of the coders save data(using spring data) as:
savedEntity = repo.save(savedEntity);
Long id = savedEntity.getId();
I am confused about why most of them assign back the returned value to the saved Entity while the following code also works exact(I have tested myself):
repo.save(savedEntity);
Long id = savedEntity.getId();
Did I miss some benefit of assigning back?
for example, let the entity be:
#Entity
public class SavedEntity {
#Id
private int id;
private String name;
//getter, setters, all arg-constructor, and no-arg constructor
}
Consider the object of SavedEntity is
SavedEntity entity = new SavedEntity(1,"abcd");
now for your first question,
SavedUser entity1 = repo.save(entity);
Long id = entity1.getId();
this entity1 object is the return object getting from the database, which means the above entity is saved in the database succesfully.
for the Second Question,
repo.save(entity);
Long id = entity.getId();//which you got it from SavedEntity entity = new SavedEntity(1,"abcd");
here the value of id is the integer you mentioned in place of id(the raw value).
Most of the time the id (primary key) is generated automatically while storing the entity to the database using strategies like AUTO, Sequence etc. So as to fetch those id's or autogenerated primary key values we assign back the saved entity.
For example:
#Entity
public class Customer {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
}
In this case you'll not pass the id externally but it will create a value for it automatically while storing the data to DB.

#Id annotation Causing duplication in list

I am using Hibernate for calling Stored procedure
Response returned by Stored procedure
receiverId fcmId source
1234 xyz android
45678 abc web
9876 fgh android
1234 ygh ios
Hibernet #EntityClass
#Entity
public class receieverDetails {
#Id
#Column(name="receiverId")
private String receiverUserId;
#Column(name="fcmId")
private String fcmIds;
private String source;
}
I am getting List of receiverDetails from database
if List contain duplicate receiverId as show is above response, 1st one is replacing the 4th details
Code for Binding
ProcedureCall procedureCall1 =
session.createStoredProcedureCall(Strings.StoredProcedureNames.GET_RECEIVER_INFO_OF_SPONSORED_MESSAGE,receieverDetails.class);
Output output1 = procedureCall1.getOutputs().getCurrent();
if(output1.isResultSet()) {
List<receieverDetails> receievers = ((ResultSetOutput) output1).getResultList();
}
i think this is causing by #Id annotation in the entity class, Because it is happening with same receiverIds only
Kindly Help me on this
In your code by providing the #Id annotation to the column receiverId, you are telling the code that this field is to be used as the primary key for the table.So, when fetching the data the issue occurs as there are duplicate values in the table for this column. Either you need to set the primary key correctly, or make this column as primary key in table and correct your code.
If you are using the same entity class to persist data and make column receiverId primary key then try using the below :
#Entity
public class receieverDetails {
#Id
#Column(name="receiverId",unique=true,nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private String receiverUserId;
#Column(name="fcmId")
private String fcmIds;
private String source;
}
unique=true in #Column is a shortcut for #UniqueConstraint(columnNames = {"receiverId"} and other particular constraints.The #GeneratedValue annotation is to configure the way of increment of the specified column(field).
or if the primary key of the table is some other field in table please correct the code to reflect the same.

Spring Data Mongo doesn't persist field value as null - This doesn't works

I already went through the link: https://jira.spring.io/browse/DATAMONGO-1107 and also I dont see option to set spring.data.mongodb.persist-null-fields=true in application.properties file.
Spring Data Mongo doesn't even persist a field having value null. How to allow to save null value if I want to do so ?
Person.java
#Builder
#Data
#AllArgsConstructor
#NoArgsConstructor
#Document
public class Person {
private String id;
private String firstName;
private String lastName;
private String emailId;
#Field
private List<Hobbies> hobbies;
}
Hobbies.java
#Builder
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Hobbies {
private String interest;
private String sports;
}
save() - This method doesn't persist data.
private void savePersons() {
Hobbies hobbies1 = Hobbies.builder().interest("Indoor").sports("Chess").build();
Hobbies hobbies2 = Hobbies.builder().interest("Loveoor").sports("Table Tennis").build();
Hobbies hobbies3 = Hobbies.builder().interest("Gamedoor").sports("Cricket").build();
Hobbies hobbies4 = Hobbies.builder().interest("Happydoor").sports("Lawn Tennis").build();
Person john = Person.builder().firstName("John")
.emailId("john.kerr#gmail.com").hobbies(Arrays.asList(hobbies1, hobbies2)).build();
Person neha = Person.builder().firstName("Neha").lastName("Parate")
.emailId("john.kerr#gmail.com").hobbies(Arrays.asList(hobbies1, hobbies2, hobbies4)).build();
repository.saveAll(Arrays.asList(john, neha));
}
I dont see lastName has been saved in the document. Also, how to save Date as null value?
One sollution is maybe to use defaults.
Your schemas can define default values for certain paths. If you create a new document without that path set, the default will kick in.
So if you want to "allow null", just make it the default value by adding to your schema definition lastName: { type: String, default: null }. When there is no lastName (aka null) you get the default value (null).
I would rethink allowing null because it would make querying complicated: Query on key: null will retrieve you all document where key is null or where key doesn't exist.
This is now possible starting with Spring Data MongoDB 3.3..
For example:
#Field(write = Field.Write.ALWAYS)
private String lastName;

Bulk data to find exists or not : Spring Data JPA

I get an Post request that would give me a List<PersonApi> Objects
class PersonApi {
private String name;
private String age;
private String pincode ;
}
And I have an Entity Object named Person
#Entity
#Table(name = "person_master")
public class Person{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
#Column(name = "name")
String name;
#Column(name = "age")
String age;
#Column(name = "pincode ")
String pincode ;
}
My record from Post request would look something like this (pseudocode representation of the data below)
[
"Arun","33","09876gh"
"James","34","8765468"
]
I need to do a bulk-validation using Spring JPA.. Give the List<PersonApi> and get a True or False based on the condition that all the entries in the PersonApi objects list should be there in the database.
How to do this ?
The selected answer is not a right one. (not always right)
You are selecting the whole database to check for existence. Unless your use case is very special, i.e. table is very small, this will kill the performance.
The proper way may start from issuing repository.existsById(id) for each Person, if you never delete the persons, you can even apply some caching on top of it.
exists
Pseudo Code:
List<PersonApi> personsApiList = ...; //from request
List<Person> result = personRepository.findAll();
in your service class you can access your repository to fetch all database entities and check if your list of personapi's is completeley available.
boolean allEntriesExist = result.stream().allMatch(person -> personsApiList.contains(createPersonApiFromPerson(person)));
public PersonApi createPersonApiFromPerson(Person person){
return new PersonApi(person.getName(), person.getAge(), person.getPincode());
}

How can I include or exclude a record according to a boolean parameter using Spring Data JPA?

I am not so into Spring Data JPA and I have the following doubt about how to implement a simple query.
I have this AccomodationMedia entity class mapping the accomodation_media on my database:
#Entity
#Table(name = "accomodation_media")
public class AccomodationMedia {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "id_accomodation")
private Long idAccomodation;
#Column(name = "is_master")
private boolean isMaster;
#Lob
#Column(name = "media")
private byte[] media;
private String description;
private Date time_stamp;
public AccomodationMedia() {
}
...............................................................
...............................................................
...............................................................
// GETTER AND SETTER METHODS
...............................................................
...............................................................
...............................................................
}
The instance of this class represents the photo associated to an accomodation (an hotel)
So as you can see in the prvious code snippet I have this field :
#Column(name = "id_accomodation")
private Long idAccomodation;
that contains the id of an accomodation (the id of an hotel on my database).
I also have this boolean field that specify if an image is the master image or not:
#Column(name = "is_master")
private boolean isMaster;
So, at this time, in my repository class I have this method that should return all the images associated to a specific hotel:
#Repository
public interface AccomodationMediaDAO extends JpaRepository<AccomodationMedia, Long> {
List<AccomodationMedia> findByIdAccomodation(Long accomodationId);
}
I want to modify this method passing also the boolean parameter that specify if have to be returned also the master image or only the images that are not master.
So I tryied doing in this way:
List<AccomodationMedia> findByIdAccomodationAndIsMaster(Long accomodationId, boolean isMaster);
but this is not correct because setting to true the isMaster parameter it will return only the master image (because it is first selecting all the Accomodation having a specific accomodation ID and then the one that have the isMaster field setted as true).
So, how can I correctly create this query that use the isMaster boolean parameter to include or exclude the AccomodationMedia instance that represent my master image?
I know that I can use also native SQL or HQL to do it but I prefer do it using the "query creation from method names"
I don't have how to test this, but essentially your final query should be:
id_accomodation = ?1 AND (is_master = ?2 OR is_master = false)
So I would try the following method signature:
findByIdAccomodationAndIsMasterOrIsMasterFalse(Long accomodationId, boolean isMaster);
I would go with two methods one for isMaster true, while second for false value like this:
List<AccomodationMedia> findByIdAccomodationAndIsMasterFalse(Long accomodationId);
List<AccomodationMedia> findByIdAccomodationAndIsMasterTrue(Long accomodationId);
Change your acommodation id as accomodationId instead of idAccomodation. When you write findByIdAccomodationAndIsMaster spring confusing findByIdAccomodationAndIsMaster
Try this this convention
#Column(name = "accomodation_id")
private Long accomodationId;

Resources