11

Based one some conditions, I have read data from MongoDB and creating a List<Document> with resultset.

List<Document> documentList = new ArrayList<Document>();

Sample Record Looks like:

documentList: [
    Document{
        { _id=5975ff00a213745b5e1a8ed9,
            u_id=,
            visblty = 1,
            c_id=5975ff00a213745b5e1a8ed8,                
            batchid=null,
            pdate=Tue Jul 11 17:52:25 IST 2017, 
            locale=en_US,
            subject = "Document2"
        }     },
    Document{
        { _id=597608aba213742554f537a6,
            u_id=,
            visblty = 1,
            c_id=597608aba213742554f537a3, 
            batchid=null,
            pdate=Fri Jul 28 01:26:22 IST 2017,
            locale=en_US,
            subject = "Document2"
        }    } 
]

Using this documentList, again i am filtering using some conditions and then I need to sort the filter record based on some conditions (which I will get in request).

List<Document> outList = documentList.stream()
                .filter(d -> d.getInteger("visblty") == 1
                && (!StringUtils.isEmpty(req.pdate())? (d.getDate(CommonConstants.PDATE).after(afterDate)): true) 
                && (!StringUtils.isEmpty(req.pdate())? (d.getDate(CommonConstants.PDATE).before(beforeDate)): true)
                .sorted().skip(4).limit()
                .collect(Collectors.toList());

Not sure how to sorted (Dynamically needs to change the sorting order based on input, it looks like "pdate by DESC" or "subject by ASC")

Like: "order by pdate DESC" or "order by pdate ASC"" or "order by subject DESC"

How to sort using Comparator object of Document class.

Note: I have tried couple of method which was suggested by the folks, but I didn't get any luck yet. Thank you in advance!

4
  • 2
    (!condition1? condition2: true) is an obfuscated variant of condition1 || condition2. You are maxing that out by repeating condition1 in two terms combined via &&. The entire filter predicate can be simplified to .filter( d -> d.getInteger("visblty")==1 && (StringUtils.isEmpty(req.pdate()) || d.getDate(CommonConstants.PDATE).after(afterDate)&&d.getDate(CommonConstants.PDATE) .before(beforeDate)) ). Though, StringUtils.isEmpty(req.pdate()) does not depend on the actual stream element, hence, could be even evaluated before the stream operation, rather than for each element. Commented Aug 2, 2017 at 10:50
  • I see your filter lambda gotten very big. I suggest you split it in parts and use function composition to add these parts together. Commented Aug 2, 2017 at 10:50
  • 1
    @MProkhorov: it’s big and redundant… I don’t know which date class it uses, but perhaps the combination of before and after could be replaced by a between call. Then, the code would be as simple as .filter(d -> d.getInteger("visblty")==1) .filter(d -> StringUtils.isEmpty(req.pdate()) || d.getDate(CommonConstants.PDATE).between(beforeDate, afterDate)) Commented Aug 2, 2017 at 10:58
  • @Holger, yes, even that is much better (after proper formatting ofc), without composing the function at all. Commented Aug 2, 2017 at 11:11

3 Answers 3

29

You can use group comparator and parallel stream as follows:

List<Document> outList = documentList.stream()
                               .filter(....)
                               .sorted(Comparator.comparing(Document::getPdate)
                                                 .thenComparing(Document::getSubject))   
                               .parallel();  
Sign up to request clarification or add additional context in comments.

2 Comments

@KayV The above example is easy to understand. But i have one clarification. What if we want to do a sorting dynamically.
@Pearl You can create custom comparator in that case. And based on some condition add the required comparator in your sorted -> comparing -> thenComparing chain
13

In terms of Java code, equivalent sorting comparators look like the following:

  1. order by pdate

    Is represented by

    Comparator.comparing(Document::getPDate)
    
  2. order by subject

    Is represented by

    Comparator.comparing(Document::getSubject)
    
  3. order by pdate, subject

    Is represented by:

    Comparator.comparing(Document::getPDate).thenComparing(Document::getSubject)

If at any point you need to have descending order, you can call reversed() on comparator, like this:

Comparator.comparing(Document::getPDate).reversed()
          .thenComparing(Comparator.comparing(Document::getSubject).reversed())

Note, that thenComparing method is overridden, providing ability to pass in:

  • a Comparator
  • a Function-extractor (works if whatever function extracts is-a Comparable)
  • a Function and a Comparator (for when extracted value is not itself a Comparable, so you cannot use its natural order and have to specify how it should be compared.

Comments

4

Instead of .sorted() try using .sorted(Comparator comparator) method.

You can create the Comparator used with .sorted(comparator) by using Comparator.comparing():

Comparator.comparing(Function keyExtractor)
    .reversed()
    .thenComparing(Function keyExtractor)

for example:

List<Document> outList = documentList.stream()
         // do your filtering here
        .sorted(Comparator.comparing(Document::getPdate).reversed()
                .thenComparing(Document::getSubject))
        .skip(4)
        .limit()
        .collect(Collectors.toList());

In this example you can use method reference Document::getPdate and Document::getSubject instead of lambda expression like d -> d.getPdate() and d -> d.getSubject()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.