spring data mongodb group by - java

I am using spring data Mongodb in my project and refer the below classes for my query on grouping the results:
Student class:
#Document(collection = "student")
public class Student {
#Id
private String id;
private String firstName;
private String lastName;
//other fields
//getters & setters
}
StudentResults (dto):
public class StudentResults {
private String firstName;
private List<String> studentIds; //I need List<Student> here
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public List<String> getStudentIds() {
return studentIds;
}
public void setStudentIds(List<String> studentIds) {
this.studentIds = studentIds;
}
}
StudentServiceImpl class:
public class StudentServiceImpl implements StudentService {
#Autowired
private MongoTemplate mongoTemplate;
public List<StudentResults> findStudentsGroupByFirstName() {
TypedAggregation<Student> studentAggregation =
Aggregation.newAggregation(Student.class,
Aggregation.group("firstName").
addToSet("id").as("studentIds"),
Aggregation.project("studentIds").
and("firstName").previousOperation());
AggregationResults<StudentResults> results = mongoTemplate.
aggregate(studentAggregation, StudentResults.class);
List<StudentResults> studentResultsList = results.getMappedResults();
return studentResultsList;
}
}
Using the above code, I am able to retrieve the List<String> studentIds successfully, but I need to retrieve List<Student> students using Aggregation.group()? Can you help?

Change your TypedAggregation part to below and add students field to StudentResults
TypedAggregation<Student> studentAggregation = Aggregation.newAggregation(Student.class,
Aggregation.group("firstName").
push("$$ROOT").as("students"));
$$ROOT will push the whole document.
Update:
TypedAggregation<Student> studentAggregation = Aggregation.newAggregation(Student.class,
Aggregation.group("firstName").
push(new BasicDBObject
("_id", "$_id").append
("firstName", "$firstName").append
("lastName", "$lastName")).as("students"));

Related

List is not in order

I converted UUID to string (String id) and put the conversion inside a method.
I also declared other String variables such as FirstName etc and put in on an ArrayList:
Code
The code does work. But I'm confused why the string email was showing second on the list.
public class StudentController {
#Autowired
StudentService studentService = new StudentService();
#GetMapping
public List<Student> displayStudent(){
return studentService.getStudent();
}
}
public class StudentService {
Student student = new Student();
private List<Student> studentList = Arrays.asList(
new Student(student.genID(),"Elvis" , "Presley" ,"Elvis#gmail.com")
);
public List<Student> getStudent(){
return studentList;
}
}
public class Student {
UUID uuid = UUID.randomUUID();
private String id;
private String FirstName;
private String LastName;
private String email;
public Student() {}
//Method Converting UUID into string
public String genID(){
id = uuid.toString();
return id;
}
public Student(String id) {
this.id = id;
}
public Student(String id, String firstName, String lastName, String email) {
this.id = id;
FirstName = firstName;
LastName = lastName;
this.email = email;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getFirstName() {
return FirstName;
}
public void setFirstName(String firstName) {
FirstName = firstName;
}
public String getLastName() {
return LastName;
}
public void setLastName(String lastName) {
LastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Expected
I expected data to be in this order
ID , FirstName , LastName , email
Actual Output JSON
JSON is an unordered collection, as specified on https://www.json.org/json-en.html , so you don't have to worry about it. It might depend on library though.
Specify the serialized order of properties
The order of properties during serialization can be defined in Jackson.
Either at class-level specifically using annotation #JsonPropertyOrder.
Or globally for your ObjectMapper using a feature:
objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
Example
In your case you can achieve expected order using the annotation on your class:
#JsonPropertyOrder({'id', 'firstName', 'lastName', 'email'})
public class Student {
// body of your class
}
Or separately with an index on your fields:
public class Student {
#JsonProperty(index=10)
private String id;
// not ordered specifically
private String firstName;
private String lastName;
#JsonProperty(index=20)
private String email;
// remainder of your class
}
See also
Jackson ObjectMapper - specify serialization order of object properties
Order of JSON objects using Jackson's ObjectMapper
Jackson JSON - Using #JsonPropertyOrder annotation to define serialized properties ordering

Not able to print all parameters in the REST object

I have a student class with few fields. For some reason, I am not getting "created" object created in Student object. When i send GET call to receive information of all student objects, I see only first 4 parameters. It is missing created field missing. What am I missing?
In Student constructor I have defined "this.created = new Date();" to assign value to created field.
public class Student {
private String firstName;
private String lastName;
private String address;
private String enrolledDepartment;
private Date created;
public Student() {
}
public Student(String firstName, String lastName, String address, String departmentName){
this.firstName = firstName;
this.lastName = lastName;
this.address = address;
this.enrolledDepartment = departmentName;
this.created = new Date();
}
// Getter and setters of all fields
}
Resource class
#Path("/students")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class StudentsResource {
List<Student> students = new ArrayList<>();
private StudentService studentService = new StudentService();
#GET
public List<Student> getProfiles() {
return studentService.getAllStudents();
}
#POST
public Student addProfile(Student profile) {
return studentService.addProfile(profile);
}
}
Service class
public class StudentService {
private List<Student> students = DatabaseClass.getStudents();
public List<Student> getAllStudents() {
return students;
}
public Student addProfile(Student student) {
students.add(student);
return student;
}
}
Database class
public class DatabaseClass {
private static List<Student> students = new ArrayList<>();
private static List<Email> emails = new ArrayList<>();
public static List<Student> getStudents() {
return students;
}
public static List<Email> getEmails() {
return emails;
}
}
I am sending a POST request using following JSON
{
"address": "Boston",
"enrolledDepartment": "health",
"firstName": "abc",
"lastName": "pqr"
}
Add this to the "default constructor":
public Student() {
this.created = new Date();
}
...the constructor, that you assume, is not called, thus created remains null.
or even:
// ...
private Date created = new Date();
public Student() {
}
public Student(String firstName, String lastName, String address, String departmentName){
this.firstName = firstName;
this.lastName = lastName;
this.address = address;
this.enrolledDepartment = departmentName;
//this.created = new Date();
}
(initialize it in the declaration.)

Saving imported objects to DynamoDB in a java application

I am trying to save an object into DynamoDB. I know that the easiest way to do this is to annotate the object with #DynamoDBDocument.
However, in my case, the objects I want to save belong to a package that I can't modify.
I am using the java sdk.
import not.my.package.Outsider;
#DynamoDBTable(tableName = "DynamoTable")
public class DynamoTable {
private Outsider outsider;
//getters...
//setters...
}
Any ideas on how I can save these objects? I do not want to save them as a string as we are using a Dynamo to SQL plugin for our business purposes.
Thanks.
Firstly, the OP doesn't have any information about partition key and sort key. The below code auto generates the partition key using annotation #DynamoDBAutoGeneratedKey. You can change it based on your use case.
Order class - Similar to DynamoTable
#DynamoDBTable(tableName = "Order")
public class Order implements Serializable {
private static final long serialVersionUID = -3534650012619938612L;
private String orderId;
private String productName;
private Integer createDate;
private Outsider outsider;
#DynamoDBHashKey(attributeName = "orderId")
#DynamoDBAutoGeneratedKey
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
#DynamoDBAttribute(attributeName = "productName")
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
#DynamoDBAttribute(attributeName = "createDate")
public Integer getCreateDate() {
return createDate;
}
public void setCreateDate(Integer createDate) {
this.createDate = createDate;
}
#DynamoDBAttribute(attributeName = "outsider")
public Outsider getOutsider() {
return outsider;
}
public void setOutsider(Outsider outsider) {
this.outsider = outsider;
}
}
Outsider class:-
The attributes in outsider class will be saved as Map attribute in DynamoDB table.
#DynamoDBDocument
public class Outsider implements Serializable{
private static final long serialVersionUID = 4449726365885112352L;
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
Code to save data:-
This code should work as long as you have dynamoDBClient object. I have used Spring to inject the object to my service class. There are multiple ways.
public Boolean createOrderWithOutsider(String productName, Outsider outsider) {
DynamoDBMapper dynamoDBMapper = new DynamoDBMapper(dynamoDBClient);
Order order = new Order();
order.setProductName(productName);
order.setOutsider(outsider);
dynamoDBMapper.save(order);
System.out.println("Order id : " + order.getOrderId());
return true;
}
Test code:-
#Test
public void createOrderWithOutsider() {
Outsider outsider = new Outsider();
outsider.setFirstName("John");
outsider.setLastName("Micheal");
Assert.isTrue(tableOperations.createOrderWithOutsider("Pepsi", outsider));
}
Connection sample:-
<bean id="amazonDynamoDB" class="com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient">
<constructor-arg ref="amazonAWSCredentials" />
<property name="endpoint" value="${amazon.dynamodb.endpoint}" />
</bean>
Autowired in service class:-
#Autowired
private AmazonDynamoDBClient dynamoDBClient;
Sample data saved in table:-

CassandraInvalidQueryException String didn't validate Composite Primary Query

I am trying to use Spring-Data-Cassandra with UserDefinedType and Compound Query Key. I am using 1.5.0.DATACASS-172-SNAPSHOT of the spring-cql and spring-data-cassandra. The code throws below exception.
Caused by: org.springframework.cassandra.support.exception.CassandraInvalidQueryException:
String didn't validate.; nested exception is com.datastax.driver.core.exceptions.InvalidQueryException:
String didn't validate.
Below is my code
#PrimaryKeyClass
public class EmployeeIdKey implements Serializable {
#PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED,name = "id")
#CassandraType(type = DataType.Name.UUID)
private UUID id;
#PrimaryKeyColumn(ordinal = 1,type = PrimaryKeyType.CLUSTERED, name = "user_id")
#CassandraType(type = DataType.Name.TEXT)
private String userId;
public EmployeeIdKey(){
id = null;
userId = null;
}
public UUID getUuId() {
return id;
}
public void setUuId(UUID uuId) {
this.id = uuId;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
}
Employee.java
#Table("employee")
public class Employee {
#PrimaryKey
private EmployeeIdKey id;
private Person person;
#Column("employee_no")
private String employeeNo;
#Column("email_ids")
private List<String> emailId;
//Getters and setters
}
Person.java
#UserDefinedType
public class Person {
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
#Column("first_name")
private String firstName;
#Column("last_name")
private String lastName;
// Getters adn setters;
}
EmployeeRepository.java
public interface EmployeeRepository extends TypedIdCassandraRepository<Employee,EmployeeIdKey> {
}
App.java
#SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class);
}
#Bean
public CommandLineRunner demo( EmployeeRepository repository) {
Employee employee = new Employee();
EmployeeIdKey key = new EmployeeIdKey();
key.setUserId("55550");
key.setUuId(UUID.randomUUID());
employee.setId(key);
List<String> emailIds = Arrays.asList("myemail#domain.com","myemail2#domain2.com");
employee.setEmailId(emailIds);
Person person = new Person("John", "Mathew");
employee.setPerson(person);
repository.save(employee);
return null;
}
}
When I use simple primary key it works well.

how create xml from java object using jaxb

How can i create following type xml in java using jaxb
<myInfo>
<firstName>MyfirstName</firstName>
<lastName>MyLstNme</lastName>
<contactList>
<contact>
<id>001</id>
<name>name1</name>
<contact/>
<contact>
<id>002</id>
<name>name2</name>
<contact/>
<contact>
<id>003</id>
<name>name3</name>
<contact/>
</ContactList>
</myInfo>
Bean Classes are..
#XmlRootElement(name = "myInfo")
#XmlAccessorType(XmlAccessType.FIELD)
public class MyInfo {
#XmlElement(name = "firstName")
public String firstName;
#XmlElement(name = "lastName")
public String lastName;
#XmlElement(name = "contactList")
public ContactList contactList;
...getter setter
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "contactList")
public class ContactList {
#XmlElement(name = "contact", type = Contact.class)
public List<Contact> list = new ArrayList<Contact>();
public ContactList() {
}
public ContactList(List<Contact> list) {
this.list = list;
}
...getter setter
}
#XmlRootElement(name = "Contact")
public class Contact {
#XmlElement(name = "id")
public String id;
#XmlElement(name = "name")
public String name;
...getter setter
And Exception
objData ToXML 2 counts of IllegalAnnotationExceptions
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
==
Class has two properties of the same name "id"
this problem is related to the following location:
at public java.lang.String java8javafx8.Contact.getId()
at java8javafx8.Contact
at public java.util.List java8javafx8.ContactList.list
at java8javafx8.ContactList
at public java8javafx8.ContactList java8javafx8.MyInfo.contactList
at java8javafx8.MyInfo
this problem is related to the following location:
at public java.lang.String java8javafx8.Contact.id
at java8javafx8.Contact
at public java.util.List java8javafx8.ContactList.list
at java8javafx8.ContactList
at public java8javafx8.ContactList java8javafx8.MyInfo.contactList
at java8javafx8.MyInfo
Class has two properties of the same name "name"
this problem is related to the following location:
at public java.lang.String java8javafx8.Contact.getName()
at java8javafx8.Contact
at public java.util.List java8javafx8.ContactList.list
at java8javafx8.ContactList
at public java8javafx8.ContactList java8javafx8.MyInfo.contactList
at java8javafx8.MyInfo
this problem is related to the following location:
at public java.lang.String java8javafx8.Contact.name
at java8javafx8.Contact
at public java.util.List java8javafx8.ContactList.list
at java8javafx8.ContactList
at public java8javafx8.ContactList java8javafx8.MyInfo.contactList
at java8javafx8.MyInfo
How create Bean Class and Bean List Class??
Ok hear you go:
Make one class call MyInfo as:
#XmlRootElement(name="myInfo")
public class MyInfo {
private String firstName;
private String lastName;
private List<Contact> contactList = new ArrayList<Contact>(0);
public MyInfo(){}
public MyInfo(String fName, String lName){
this.firstName = fName;
this.lastName = lName;
}
#XmlElement(name = "firstName")
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#XmlElement(name="lastName")
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public List<Contact> getContactList() {
return contactList;
}
#XmlElement(name = "contactList")
public void setContactList(List<Contact> contactList) {
this.contactList = contactList;
}
}
write another class called Contact as:
public class Contact {
private int id;
private String name;
public Contact(){}
public Contact(int id, String name){
this.id = id;
this.name = name;
}
#XmlElement(name = "id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#XmlElement(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Marshell it with JAXB (create XML) as:
public class Test {
public static void main(String[] args){
Contact c1 = new Contact(1, "first");
Contact c2 = new Contact(2, "second");
MyInfo info = new MyInfo("Shekhar", "Khairnar");
info.getContactList().add(c1);
info.getContactList().add(c2);
try {
JAXBContext jaxbContext = JAXBContext.newInstance(MyInfo.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(info, System.out);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
In above eg. I just print the xml output on console you can write in a file also.
out put will be:
<myInfo>
<firstName>Shekhar</firstName>
<lastName>Khairnar</lastName>
<contactList>
<id>1</id>
<name>first</name>
</contactList>
<contactList>
<id>2</id>
<name>second</name>
</contactList>
You can do the following:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class MyInfo {
private String firstName;
private String lastName;
#XmlElementWrapper
#XmlElement(name="contact")
private List<Contact> contactList;
// getters & setters
}
Things to note:
JAXB is configuration by exception so you only need to annotate where you want the XML representation to differ from the default.
By default JAXB treats public fields and properties as mapped. If you want to treat only fields as mapped you should specify #XmlAccessorType(XmlAccessType.FIELD).
The mapped fields can be private.
#XmlElementWrapper is used to add a grouping element to a collection.
When #XmlElement is used on a collection it applies to each item in the collection.

Categories

Resources