Spring Data MongoDB Unique Embedded Fields - java

So, I have one #Document class which has a embedded pojo field which I want it to be unique for the document based on a key in the pojo class. I tried using #CompoundIndex & #Indexed to mark it as unique but it doesn't seem to work.
#Document
public class Project {
private String id;
private String name;
private List<Details> details = new ArrayList<>();
}
public class Details{
private String key;
private String description;
}
What I want to achieve is that a project document should have unique details field in it with it's key being unique. But when I have the
#CompoundIndexes({ #CompoundIndex(name = "details_key", def = "{'details.key':1}", unique = true) }) on the Project class it doesn't work. Which I thought it should. Or am I wrong somewhere with my understanding. As I am new to this.

Related

Springboot save hashmap in mongo repository

I have an entity class that has a hashmap field :
#Document(collection = "tenant")
#Getter() #Setter #ToString
public class Tenant extends DateAudit {
#Id
private String tenantId=UUID.randomUUID().toString();
#Indexed(unique = true)
#Field("name")
private String name;
#Field("app_registration_list")
private HashMap<String, ArrayList<AppRegistration>> appRegistrationList = new HashMap<String, ArrayList<AppRegistration>>();
}
But while adding data to the field appRegistrationList I get this error on my controller:
"Invalid BSON field name $hashCodeCache"
I am using Microsoft Cosmos Db instead of mongoDb. As read in another issue, my key is also a string value. Not sure what can be changed. I am open to changing the data type that will still satisfy this key and list purpose.
EDIT:
I can see this code working if I change the field to the following:
#Field("app_registration_list")
private HashMap<String,String> appRegistrationList = new HashMap<>();
However, this doesn't solve the purpose I was looking for.

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

Web application spring boot and angular 5

I am making a simple CRUD application using Spring boot and MongoDB, the problem that I am facing is that I don't know how to define the model classes.
My application should be like this:
A site has some characteristics such as an ID, region, city, ... and contains 4 parts (cellulars) that each has its own characteristics. Any help would be appreciated.
This is what I have so far:
public class Site {
#Id
String siteId;
String projectPhase;
String region;
String city;
String siteName;
String newSiteName;
String clusterName ;
String longitude ;
String lattitude ;
#OneToMany(mappedBy = "siteId")
List L;
What I want to know is how do I associate another class inside this one.
Annotations like #OneToMany are typically used within JPA-context, and are unnecessary when using Spring Data MongoDB. This is also mentioned by the documentation:
There’s no need to use something like #OneToMany because the mapping framework sees that you want a one-to-many relationship because there is a List of objects.
You have a few options when you want to define one-to-many relations when using MongoDB. The first of them is to define them as embedded objects within the same document:
#Document
public class Site {
#Id
private String id;
private String city;
private String region;
private List<Part> cellulars;
}
public class Part {
private String characteristic1;
private String characteristic2;
}
This means that the parts do not exist on their own, so they don't need their own ID either.
Another possibility is to reference to another document:
#Document
public class Site {
#Id
private String id;
private String city;
private String region;
#DBRef
private List<Part> cellulars;
}
#Document
public class Part {
#Id
private String id;
private String characteristic1;
private String characteristic2;
}
In this case, parts are also separate documents, and a site simply contains a reference to the part.

Flink cassandraOutputFormat tuple needs frozen value

I have a flink project that will be inserting data in a cassandra table as a batch job. I already have a flink stream project where it is writing a pojo to the same cassandra table, but cassandraOutputFormat needs the data as a Tuple (hope that is changed to accept pojos like CassandraSink does at some point). So here is the pojo that I have that:
#Table(keyspace="mykeyspace", name="mytablename")
public class AlphaGroupingObject implements Serializable {
#Column(name = "jobId")
private String jobId;
#Column(name = "datalist")
#Frozen("list<frozen<dataobj>")
private List<CustomDataObj> dataobjs;
#Column(name = "userid")
private String userid;
//Getters and Setters
}
And the dataset of tuple I am making from this pojo:
DataSet<Tuple3<String, List<CustomDataObj>, String>> outputDataSet = listOfAlphaGroupingObject.map(new AlphaGroupingObjectToTuple3Mapper());
And here is the line that triggers the output as well:
outputDataSet.output(new CassandraOutputFormat<>("INSERT INTO mykeyspace.mytablename (jobid, datalist, userid) VALUES (?,?,?);", clusterThatWasBuilt));
Now the issue that I have is when I try to run this, I get this error when it tries to output it to the cassandra table:
Caused by: com.datastax.driver.core.exceptions.CodecNotFoundException:
Codec not found for requested operation: [frozen<mykeyspace.dataobj> <-> flink.custom.data.CustomDataObj]
So I know when it was a pojo, I just had to add the #Frozen annotation to the field, but I don't know how to do that for a tuple. What is the best/proper way to fix this? Or am I doing something unnecessary because there is actually a way to send pojos through the cassandraOutputFormat I just haven't found?
Thanks for any and all help in advance!
EDIT:
Here is the code for the CustomDataObj class too:
#UDT(name="dataobj", keyspace = "mykeyspace")
public class CustomDataObj implements Serializable {
#Field(name = "userid")
private String userId;
#Field(name = "groupid")
private String groupId;
#Field(name = "valuetext")
private String valueText;
#Field(name = "comments")
private String comments;
//Getters and setters
}
EDIT 2
Including the table schema in cassandra that the CustomDataObj is tied to and the mytablename schema.
CREATE TYPE mykeyspace.dataobj (
userid text,
groupid text,
valuetext text,
comments text
);
CREATE TABLE mykeyspace.mytablename (
jobid text,
datalist list<frozen<dataobj>>,
userid text,
PRIMARY KEY (jobid, userid)
);
Add UDT Annotation on CustomDataObj class
#UDT(name = "dataobj")
public class CustomDataObj {
//......
}
Edited
Change jobid Annotation to #Column(name = "jobid") and dataobjs Frozen Annotation to #Frozen
#Table(keyspace="mykeyspace", name="mytablename")
public class AlphaGroupingObject implements Serializable {
#Column(name = "jobid")
private String jobId;
#Column(name = "datalist")
#Frozen
private List<CustomDataObj> dataobjs;
#Column(name = "userid")
private String userid;
//Getters and Setters
}
I believe I have found a better way than having to provide a tuple to the cassandraOutputFormat, but it technically still doesn't answer this question so I won't mark this as the answer. I ended up using cassandra's object mapper so I can just send the pojo to the table. Still need to validate that data got to the table successfully and that everything is working properly with the way it is implemented, but I felt this would help anyone who is facing a similar problem.
Here is the doc that outlines the solution: http://docs.datastax.com/en/developer/java-driver/2.1/manual/object_mapper/using/

Indexing composite object in spring mongodb

I have a composite object that I wish to store in mongodb (using spring annotations). The object is as follows:
#Document(collection="person")
class Person {
#Id
private String id;
private Address address;
private String name;
}
and the composite class Address:
#Document
class Address {
#Indexed
private Long countryId;
private String street;
#Indexed
private String city
}
I need both country and city to be indexed as part of the person collection. Alas, no index is created for them. Any ideas how to create the index?
I have tried the following which works but is not elegant:
#Document(collection="person")
#CompoundIndexes({
#CompoundIndex(name = "countryId", def = "{'address.countryId': 1}")
})
class Person {
You can set up multiple secondary indexes, if you wish. This would be a good place to start.

Categories