0

I want to be able to pass the id of a model object to a method and then compare it with all other objects of that model type to see if it certain attributes match. I know you can do more conventional queries with Models Finder but I will need to use some custom methods I have wrote to do the comparison. Is there a way to go through all existing model objects, comparing their attributes against the attributes of the object concerned and storing matches is some sort of list. Is Finder capable of doing this?

I am using EBean.

Update:

So my model is actually slightly more complex than the books example I had previously used. It is a model to store information on journeys users make. Four of the attributes of the model are shown below:

    public Double sLat;
    public Double sLon;
    public Double eLat;
    public Double eLon;

These doubles represent the latitude and longitude of the starting point of the journey and latitude and longitude of the end point. I am using the Harvesine Formula described in a previous post: How can I measure distance and create a bounding box based on two latitude+longitude points in Java?

So in my model I will use the method below to calculate the distance between two points:

public static double distFrom(double lat1, double lng1, double lat2, double lng2) {

    double earthRadius = 3958.75;
    double dLat = Math.toRadians(lat2-lat1);
    double dLng = Math.toRadians(lng2-lng1);
    double sindLat = Math.sin(dLat / 2);
    double sindLng = Math.sin(dLng / 2);
    double a = Math.pow(sindLat, 2) + Math.pow(sindLng, 2)
            * Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2));
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    double dist = earthRadius * c;

    return dist;
}

I have already tested this with some hardcoded dummy data to see that it works as expected using this method:

public static void journeyCompare(double lat1, double lng1, double lat2, double lng2,
                                      double lat3, double lng3, double lat4, double lng4) {

        double startMatch = distFrom(lat1, lng1, lat3, lng3);
        if(startMatch<=5) {
            System.out.println("Starting points are within five miles of each other");
            double endMatch = distFrom(lat2, lng2, lat4, lng4);
            if(endMatch<=5) {
                System.out.println("Start and end points are within five miles of each other!!! JOURNEY MATCH");
            }
            else {
                System.out.println("End points are too far apart");
            }
            }
            else {
            System.out.println("Starting points are too far apart");
            }

    }

So my question is really how would I be able to use these methods - taking one journey, the four doubles representing its points and compare it against all other journeys. I'm not sure if there is a way to split this up using EBean finder or not.

Further Update:

So I think I'm nearly there now I'm getting a play error though: No QueryString binder found for type Double. My new matcher method:

public static List<Journey> matcher(Double startLat, Double startLon, Double endLat, Double endLon) {

    //Create a list to store matched journeys
    List<Journey> matchList = new ArrayList<Journey>();

    //Create a list that stores all pre-existing journeys
    List<Journey> allJourneys = new ArrayList<Journey>();
    allJourneys = find.all();

    for(Journey journey : allJourneys) {
        double distanceBetweenStart = distFrom(startLat, startLon, journey.sLat, journey.sLon);

        //if the starting points are within 3 miles of each other
        if(distanceBetweenStart <= 3) {
            //check end points
            double distanceBetweenEnd = distFrom(endLat, endLon, journey.eLat, journey.eLon);
            if(distanceBetweenEnd <= 3) {
                matchList.add(journey);
            }
        }
    }
            return matchList;
}
Community
  • 1
  • 1
  • Are you using Ebean or JPA? Would you also be able to post the src to your Book class, as well as identify which search criteria you are looking to match? – Jeff LaJoie Mar 26 '13 at 17:40
  • I am using EBean and I have edited the question to include my Book class. –  Mar 26 '13 at 19:27
  • Added an ebean implementation, please note if you so choose, you are allowed to use your Books.all() call in order to generate the list of all Books, and from there remove any from the list which do not meet your requirements. – Jeff LaJoie Mar 26 '13 at 22:24
  • Thanks for your response. I updated my question because the model example I was giving wasn't really helping with my question. I added the actual model I am using and the issue that I have regarding using my own methods to perform queries on the model objects. –  Mar 28 '13 at 13:32
  • I see, I've run into that error before as well. I recall creating a wrapper for it, which I was directed to on another question on SO, http://stackoverflow.com/questions/10286725/how-to-bind-double-parameter-with-play-2-0-routing. Though I think, at least for the scope of this question, I can't answer "Comparing all model objects" any more fully. – Jeff LaJoie Mar 28 '13 at 18:12
  • No, I appreciate your input, it has been a big help. I found myself looking at that page. However whenever I create the custom binder it is still being recognized as a string so I am unable to perform arithmetic on the new type. –  Mar 28 '13 at 18:16

1 Answers1

2

Assuming you're using JPA and a library such as Hibernate for persistence, there are a few ways you could approach this.

public static List<Book> findMatch(Book id){
    List<Book> allBooks = JPA.em().createQuery("FROM Book").getResultList();
    List<Book> matchedBooks = new ArrayList<Book>(); 
    for(Book b : allBooks){
        if(isPossibleMatch(b, id)) //assuming you define a .isPossibleMatch() method
            matchedBooks.add(b);
    }
    return matchedBooks;
}

or

public static List<Book> findMatch(Book id){
    Query query = JPA.em().createQuery("SELECT b FROM Book b WHERE b.fieldOne = :fieldOne AND b.fieldTwo : fieldTwo");
    query.setParameter("fieldOne", id.fieldOne);
    query.setParameter("fieldTwo", id.fieldTwo);
    return query.getResultList();
}

EDIT: Going to leave the above for completeness, but here's an edit for an Ebean solution.

As shown by the examples at http://www.playframework.com/documentation/2.0.4/JavaEbean, you can implement a static 'find' field to your Book class.

public static Finder<Long,Book> find = new Finder<Long,Book>(Long.class, Book.class);

From there, it would very similarly match the above JPA code, however the way in which you acquire the list of all Book objects would differ by calling your

Book.find.all()

However, if you would prefer to be able to do in your comments, such as finding the books between $2.50 and $4.50 you could write the Query using the Finder as follows:

Book.find.where().between("price", 2.5, 4.5).findList();

The where() method should prove to be useful for you, and can be found at http://www.avaje.org/static/javadoc/pub/com/avaje/ebean/Query.html#where%28%29

Jeff LaJoie
  • 1,725
  • 2
  • 17
  • 27