Sorted order in Flux of custom class - reactive-programming

Suppose I have a class Student with attributes name and height.
class Student{ String name; double height;}
If I have a flux of objects of students and I want to the output to be sorted in ascending order of the student's name, then how do I do that?

Suppose you have an array of student objects as follows:
Student[] students = {studentObj1, studentObj2, studentObj3};
You just need to use a Comparator, which in Java 8/ reactive programming can be written as a lambda function, in the sort method provided by Flux.
Here obj1 and obj2 are the objects of Student class which are compared to each other.
obj1.compareTo(obj2) sorts them in ascending order.
Flux.fromIterable (Arrays.asList(students)).sort( (obj1, obj2) -> obj1.getName().compareTo(obj2.getName()));

Accepter answer works but instead of rolling your own comperator you can also use method references, given that the class has getters:
class Student {
String name;
double height;
public String getName() {
return name;
}
// more getters
}
You can then do:
Flux.fromIterable(Arrays.asList(students)).sort(Comparator.comparing(Student::getName))

Accepted answer is OK but I'd suggest a different way.
If what you have is an array of Students, then you can just sort using Arrays.sort and then create a Flux from the sorted array calling Flux.fromArray.
But if you have a Flux of student, not array, Flux have a operator to do that job specifically - Flux.collectSortedList
Flux studentFlux = Flux.just(studentOne,studentTwo);
studentFlux.collectSortedList((studentObj1, studentObj2) -> studentObj1.getName().compareTo(studentObj2.getName()))

Related

Select nested property from MongoDB repository with Spring Boot

I like the parsing of method names in the MongoRepository so I don't have to write queries. But I was wondering if there is a way to use this pattern to only select a certain (nested) field.
My Document looks like:
#Document(collection = "elements")
public class ElementEntity {
#Id
private String id;
private String type;
private MetaData metaData;
private String json;
}
public class MetaData {
private String title;
private String description;
private final List<String> keywords = new ArrayList<>();
}
I can search ElementEntities by keyword with this:
List<ElementEntity> findByMetaDataKeywords(String keyword);
I now want to get a list of possible keywords, but I don't find any documentation on how or if it is even possible with the method name pattern. I was hoping something like this might work, but it doesn't:
List<String> getDistinctMetaDataKeywordsAsc();
Is there a way to achieve this with just an interface method, or do I need to write a (SQL?) query?
EDIT based on a comment in one of the answers:
Assuming I have two documents in my elements collection:
has the keywords: "disclaimer" and "legal"
has the keywords: "footnote" and "legal"
I want to have a method that returns me a List with the three distinct keywords in alphabetic order: "disclaimer", "footnote", "legal"
try this
List<ElementEntity> findByMetaData_Keywords(List<String> keywords);

Nested query in mongodb using spring data

I am trying to use nested Mongodb query but it does not work.
It is similar to Spring data mongodb query for subdocument field
But suggestions mentioned there does not work.
Please find my documents below.
#Document
public class Ticket {
#Id
private String id;
#DBRef
#CascadeSave
private Customer customer;
// getters and setters
}
#Document
public class Customer {
#Id
private String id;
private String firstName;
// getters and setters
}
public interface TicketRepository extends MongoRepository<Ticket, String> {
public List<Ticket> findByCustomerFirstName(String firstName);
}
I tried both findByCustomerFirstName and findByCustomer_FirstName but it does not work. Any suggestions ?
These suggestions are right it should work...
Official docs explains it as you did it:http://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#repositories.query-methods.query-property-expressions
Property expressions can refer only to a direct property of the
managed entity, as shown in the preceding example. At query creation
time you already make sure that the parsed property is a property of
the managed domain class. However, you can also define constraints by
traversing nested properties. Assume a Person has an Address with a
ZipCode. In that case a method name of
List<Person> findByAddressZipCode(ZipCode zipCode);
creates the
property traversal x.address.zipCode
Just one thing, remove #Document from Customer and try it, Mongodb didn't support join queries (I'm not sure if now it does)... so you're document should be Ticket and it must have a embbebed document Customer as a inner object and not in a different document.

Entity Framework - To sum reference object properties

I have the following models which represent my table relationship.
public class A { List<B> B_List }
public class B { public int amount }
I was wondering if it is possible to get top 5 class A objects order by "amount".
I was hoping there is a way to write an EF query to avoid pulling all A objects from database.
I think #Bilal's answer is close, but may not get you exactly what you want. By the way, you haven't been clear on what you mean by "top 5 A objects order by Amount". Each A object has multiple amounts. Are you wanting the top 5 A objects based on the maximum amount? If so, then try this ...
dbContext.AList
.OrderByDescending(a => a.B_List.Sum(b => b.amount))
.Take(5);

MongoDB and NoRM - Querying collection against a list of parameters

I need to query a collection based on a list of parameters.
For example my model is:
public class Product
{
string id{get;set;}
string title{get;set;}
List<string> tags{get;set;}
DateTime createDate{get;set;}
DbReference<User> owner{get;set;}
}
public class User
{
string id{get;set;}
...other properties...
}
I need to query for all products owned by specified users and sorted by creationDate.
For example:
GetProducts(List<string> ownerIDs)
{
//query
}
I need to do it in one query if possible not inside foreach. I can change my model if needed
It sounds like you are looking for the $in identifier. You could query products like so:
db.product.find({owner.$id: {$in: [ownerId1, ownerId2, ownerId3] }}).sort({createDate:1});
Just replace that javascript array [ownerId1, ...] with your own array of owners.
As a note: I would guess this query is not very efficient. I haven't had much luck with DBRefs in MongoDB, which essentially adds relations to a non-relational database. I would suggest simply storing the ownerID directly in the product object and querying based on that.
The solution using LINQ is making an array of user IDs and then do .Contains on them like that:
List<string> users = new List<string>();
foreach (User item in ProductUsers)
users .Add(item.id);
return MongoSession.Select<Product>(p => users .Contains(p.owner.id))
.OrderByDescending(p => p.createDate)
.ToList();

Having a list of strings represented in a database using ORMLite

First of I am new to ORMLite. I would like my model class to have a field which is a list of strings, that would eventually hold a list of tags for my model object.
Which ORMLite annotations should I use?
Firstly I don't want to have a table of all tags, and then use the #ForeignCollectionField.
Also I thought of using the #DatabaseField(dataType=DataType.SERIALIZABLE) annotation, but it turns out that List<String> doesn't implement the Serializable interface.
What are your suggestions?
First of all, List doesn't implement Serializable but ArrayList certainly does as well as most of the common collection implementations. But storing a huge list is probably not the best of doing this from a pure object model standpoint.
So why don't you want to have a table of all tags? That's the best way from a pure model standpoint. It will require a 2nd query if you need them every time. That's the way hibernate would store a list or array of tags.
After reading your comment #creen, I still think you do want a table of tags. Your model class would then have:
#ForeignCollectionField
Collection<Tag> tags;
The tags table would not have a single tag named "red" with multiple model classes referring to it but multiple "red" entries. It would look like:
model_id name
1 "red"
1 "blue"
2 "red"
3 "blue"
3 "black"
Whenever you are removing the model object, you would first do a tags.clear(); which would remove all of the tags associated with that model from the tags table. You would not have to do any extra cleanup or anything.
No need to go for #ForeignCollectionField for simple String Array
Change your code
#DatabaseField(dataType=DataType.SERIALIZABLE)
List<String> users;
to
#DatabaseField(dataType = DataType.SERIALIZABLE)
String[] users;
Database doesn't want to store dynamically grow able arrays. That is the reason it allows only static array like string[] and not List.
I added two properties... one that gets written to the database as a csv string and the other that translates this:
[Ignore]
public List<string> Roles
{
get
{
return new List<string>(RolesCsv.Split(new char[] { ',' }));
}
set
{
RolesCsv = string.Join(",", value);
}
}
public string RolesCsv { get; set; }