Spring Data MongoDB how to set index ttl from system property - java

Preferably, using the #Indexed annotation, or some other declarative way, is it possible to inject a system property, preferably using SPeL.
I have tried the following but found expireAfterSeconds gives error because it wants an int:
#Data
#Document(collection = "#{#xyzUpdates.collectionName}")
public class UpdatesFromXyz {
#Id
#Field("resourceId")
private UUID resourceId;
#Indexed(expireAfterSeconds = "#{#xyzUpdates.maxRecords}")
private LocalDate updateDate;
}
and my properties class:
#ConfigurationProperties("xyz.updates")
#Getter
#Setter
#Component
public class XyzUpdates {
private String collectionName = "updatesFromXyz";
private int maxRecords;
}

Since SpringData MongoDB 2.2 you can use expireAfter which accepts numeric values followed by their unit of measure or a Spring template expression.

Related

How can I write SQL query in JPA repository with Spring Boot?

I'm doing a spring boot experiment and using MySQL.
For example, if I have a list of users, but I want to get the specified names, how can I write the SQL query that only indicates this situation?
This is my model class :
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name="users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public long id;
#Column(name="first_name")
public String name;
#Column (name="last_name")
public String last_name;
}
This is my JPA interface :
public interface CommentRepository extends JpaRepository<User , Long >{
// All C.R.U.D database methods
}
Finally, my controller area is as below :
#RestController
#RequestMapping(path="/api/v1/users")
public class CommentController {
#Autowired
CommentRepository repository ;
#GetMapping(path="/list")
public List<User> users() {
return repository.findAll();
}
}
Maybe you didn't understand my problem, I just want to write a customizable query of my own.
For example, I want to pull the data with the method I designed, while I normally pull the data by numbers with the find by id method.
You can either use methods that will be translated into queries or write your queries in the #Query annotation.
Please read the docs: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories

Can we use Composite Primary Key Mapping in spring data elastic search

I have an entity 'Product' and I want the primary key in ES to be used as a combination of 'id' and 'name' attributes. How can we do that using spring data elastic search.
public class Product {
#Id
private String id;
#Id
private String name;
#Field(type = FieldType.Keyword)
private Category category;
#Field(type = FieldType.Long)
private double price;
#Field(type = FieldType.Object)
private List<ValidAge> age;
public enum Category {
CLOTHES,
ELECTRONICS,
GAMES;
}
}
One way to achieve this would be the following:
first rename your id property, I changed it to documentId here. This is necessary, because in Spring Data
Elasticsearch an id-property can be either annotated with #Id or it can be namend id. As there can only be one
id-property we need to get this out of the way. It can have the name id in Elasticsearch, set by the #Field
annotation, but the Java property must be changed.
second, add a method annotated with #Id and #AccessType(AccessType.Type.PROPERTY) which returns the value you
want to use in Elasticsearch.
third, you need to provide noop-setter for this property. This is necessary because Spring Data Elasticsearchsoe
not check the id property to be read only when populating an entity after save or when reading from the index.
This is a bug in Spring Data Elasticsearch, I'll create an issue for that
So that comes up with an entity like this:
#Document(indexName = "composite-entity")
public class CompositeEntity {
#Field(name="id", type = FieldType.Keyword)
private String documentId;
#Field(type = FieldType.Keyword)
private String name;
#Field(type = FieldType.Text)
private String text;
#Id
#AccessType(AccessType.Type.PROPERTY)
public String getElasticsearchId() {
return documentId + '-' + name;
}
public void setElasticsearchId(String ignored) {
}
// other getter and setter
}
The repository definition would be straight forward:
public interface CompositeRepository extends ElasticsearchRepository<CompositeEntity,
String> {
}
Remember that for every method that needs an Elasticsearch Id, you'll need to create like it's done in the entity
class.
I am not sure about spring data elasticsearch but spring jpa provides the facility of defining composite primary key by using #IdClass where we can define a separate class(let us say class A) in which we can define all the fields which we want to be a part of composite key Then we can use #IdClass(A.class) in entity class and use #Id annotation on all the fields which should be the part of the composite key
you can refer to this article, although I am not sure whether the same concept will be applicable for spring data es - https://www.baeldung.com/jpa-composite-primary-keys

Binding map from config yaml

In spring boot project i am trying to bind a map from yaml file. I have tried most of the solutions to bind map but getting following error:
Property: order.events
Value: null
Reason: must not be empty
Action:
Update your application's configuration
As you can see on config class i have getter/setter through lombok and inner class is a static class.
#Data
#Validated
#ConfigurationProperties(prefix = "order", ignoreUnknownFields = false)
public class OrderConfig {
private String clientKey;
private String apiVersion;
private String endpoint;
#Valid
#NotEmpty
private Map<String, Event> events;
#Data
public static class Event {
#NotBlank
private String action;
#NotBlank
private String eventName;
}
}
By using lombok i already have all necessary getter and setter methods. My config yaml file is:
order:
clientKey: client_1
apiVersion: 1.0.0
endpoint: https://www.ordertest.com/api
events:
order.create:
action: track
eventName: purchase
order.place:
action: track
eventName: purchase
And my Application class:
#SpringBootApplication
#EnableConfigurationProperties(OrderConfig.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
You need to encode them in double quotes with square brackets Relaxed Binding
When binding to Map properties, if the key contains anything other than lowercase alpha-numeric characters or -, you need to use the bracket notation so that the original value is preserved. If the key is not surrounded by [], any characters that are not alpha-numeric or - are removed.
order:
clientKey: client_1
apiVersion: 1.0.0
endpoint: https://www.ordertest.com/api
events:
"[order.create]":
action: track
eventName: purchase
"[order.place]":
action: track
eventName: purchase
And also you need to annotate #Configuration on OrderConfig class
Sometimes, classes annotated with #ConfigurationProperties might not be suitable for scanning, for example, if you’re developing your own auto-configuration. In these cases, you can specify the list of types to process on any #Configuration class
If you really want your keys to be order.create and order.place then you have to specify them as "[order.create]" and "[order.place]" in order to escape the periods. Otherwise you should be able to work with just create and place.
I couldn't figured why i had that problem and wanted to give a shot with the latest Spring boot version 2.2.0 which they introduced ConstructorBinding.
I have changed my config class to following version and its fixed.
#Data
#Validated
#ConstructorBinding
#ConfigurationProperties(prefix = "order", ignoreUnknownFields = false)
public class OrderConfig {
private final String clientKey;
private final String apiVersion;
private final String endpoint;
#Valid
#NotEmpty
private final Map<String, Event> events;
#Data
#ConstructorBinding
public static class Event {
#NotBlank
private final String action;
#NotBlank
private final String eventName;
}
}

Null fields when I use #JsonProperty for retrieve object from MongoDB by Spring data

I have some problem with Spring JPA, MongoDB and Jackson when I use #JsonProperty to use a different name for the json/db and java field.
I receive json and save them into collections, for example
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Document(collection="message")
public class Message implements java.io.Serializable{
private static final long serialVersionUID = 1L;
#Id
private String id;
#JsonProperty("raw")
private Raw raw;
#JsonProperty("meta")
private Meta meta;
}
with Raw :
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Document(collection="raw")
public class Raw {
private String dlc;
#JsonProperty("can_id")
private String canId;
#JsonProperty("can_data")
private String canData;
}
I'm using lombok for the get,set and constructor. I had the message into database before change the field name (using for instance canData instead of can_data) and when I retrieved the object from database this renamed fields were null. So I removed the message and stored again and finally work, I made this because into mongodb I see _class:"com.domain.Message".
This is the first problem: every time I change my java class all the stored data give me this problem?
But I have problem even with manually inserted json into Mongodb: the fields where I use #JsonProperty are null when I make the query like this:
#Query("{ 'can_id' : ?0 }")
Severity findByCanId(String canId);
Severity is so:
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Document(collection="severity")
public class Severity implements java.io.Serializable{
private static final long serialVersionUID = 1L;
#JsonProperty("can_id")
#Indexed
private String canId;
#JsonProperty("can_name")
private String canName;
private Integer ss;
private Integer ps;
private Integer fs;
private Integer os;
}
The query return me a Severity object with canId and canName null.
Do you know how can I fix this problem? Thanks
For the name of field into database I fix using #Field("can_id") but the problem about the changing of java class stil present
You should replace #JsonProperty with #BsonProperty

#Indexed on nested property not working in Spring-data for mongo

I have the following object structure:
#Document(collection = "user")
#TypeAlias("user")
public class User {
#Id
private ObjectId id;
private Contact info = new Contact();
}
and here is the Contact pojo:
public class Contact {
#Indexed(unique = true)
private String mail;
}
But for some reasons not known to me, I don't see Spring-data creating a unique index for the property info.mail
To summarize, I have this json structure of user object:
{_id:xxxxx,info:{mail:"abc#xyz.shoes"}}
And I want to create a unique index on info.mail using Spring data with the above pojo structure. Please help.
As far as I remember, annotating embedded fields with #Indexed will not work. #CompoundIndex is the way to go:
#Document(collection = "user")
#TypeAlias("user")
#CompoundIndexes({
#CompoundIndex(name = "contact_email", def = "{ 'contact.mail': 1 }", unique = true)
})
public class User {
#Id
private ObjectId id;
private Contact info = new Contact();
}
In my case I had a fresh spring boot application 2.3.0 with just #Document, #Id and #Indexed annotations. I was able to retrieve and insert documents but it refused to create the index other than the PK. Finally I figured that there is a property that you need to enable.
spring.data.mongodb.auto-index-creation = true
As a matter of fact it even works on nested objects without #Document annotation.
Hope this helps :)
Obsolete answer, this was with and older version of mongodb 1.x.
Had the same issue, it seems that your Contact class is missing the #Document annotation i.e.
#Document
public class Contact {
#Indexed(unique = true)
private String mail;
}
Should work, quote from the spring mongodb reference
Automatic index creation is only done for types annotated with #Document.
Extending #Xenobius's answer:
If any configuration extending AbstractMongoClientConfiguration is set, MongoMappingContext will back off. The result is:
spring.data.mongodb.auto-index-creation = true will not be effective
You will need add this into your own configuration:
#Override
protected boolean autoIndexCreation() {
return true;
}
ref: https://github.com/spring-projects/spring-boot/issues/28478#issuecomment-954627106

Categories