Ebean query for string that start with then contains a specific string











up vote
1
down vote

favorite












I got a little issue here with a query for a string to search in DB for auto-complete functionality, the problem that I got that I need first results to be all statements that "Start" with then the statements that contain that string!



For example: If I got the following records in a table in the database:





  1. Awesome service to provide

  2. Something else here

  3. Extra Service

  4. My Service is awesome

  5. Service Provided

  6. Zoo Services




And I started to type "Service" I need No. 5 to show first, then the rest of items ( 1, 3, 4, 6)



I know how to do that in MySQL, something like:



select * from `services` where `name` like '%Service%' order by `name` like 'Service%' desc;


Or maybe like the ways mentioned here: MySQL order by "best match"



but I need to do that in Ebean.
I tried:



return Service.find.query().where().icontains("name", search).findList()


But this return with 1, 3, 4, 5, 6,



and now I do the following:



final List<Service> list = Service.find.query().where()
.istartsWith("name", search)
.orderBy("name").findList(); // First query

list.addAll(Service.find.query().where()
.icontains("name", search)
.not().istartsWith("name", search)
.orderBy("name").findList()); // Then add the results for the second query
return list;


This will do the job, 5, 1, 3, 4, 6 but I don't like it, because I hit database with 2 queries, also I do exclude the first query in complex data type query in the second query, but anyway, is it a correct way? if not, do you have a suggestion or solution for a better way?



Table:



CREATE TABLE `services` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE services ADD UNIQUE `uq_services_name`(name);


EBean entity
Service.java:



@Entity
@Table(name = "services")
public class Service extends BaseModel<Service> {
public static Finder<Integer, Service> find = new Finder<>(Service.class);

@Column(nullable = false, unique = true)
private String name;

// ... setters and getters

}


BaseModel.java:



@MappedSuperclass
public abstract class BaseModel<T> extends Model {

@Id
@Column
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;

public final Integer getId() {
return id;
}

@SuppressWarnings("unchecked")
public final T setId(Integer id) {
this.id = id;
return (T) this;
}
}









share|improve this question




























    up vote
    1
    down vote

    favorite












    I got a little issue here with a query for a string to search in DB for auto-complete functionality, the problem that I got that I need first results to be all statements that "Start" with then the statements that contain that string!



    For example: If I got the following records in a table in the database:





    1. Awesome service to provide

    2. Something else here

    3. Extra Service

    4. My Service is awesome

    5. Service Provided

    6. Zoo Services




    And I started to type "Service" I need No. 5 to show first, then the rest of items ( 1, 3, 4, 6)



    I know how to do that in MySQL, something like:



    select * from `services` where `name` like '%Service%' order by `name` like 'Service%' desc;


    Or maybe like the ways mentioned here: MySQL order by "best match"



    but I need to do that in Ebean.
    I tried:



    return Service.find.query().where().icontains("name", search).findList()


    But this return with 1, 3, 4, 5, 6,



    and now I do the following:



    final List<Service> list = Service.find.query().where()
    .istartsWith("name", search)
    .orderBy("name").findList(); // First query

    list.addAll(Service.find.query().where()
    .icontains("name", search)
    .not().istartsWith("name", search)
    .orderBy("name").findList()); // Then add the results for the second query
    return list;


    This will do the job, 5, 1, 3, 4, 6 but I don't like it, because I hit database with 2 queries, also I do exclude the first query in complex data type query in the second query, but anyway, is it a correct way? if not, do you have a suggestion or solution for a better way?



    Table:



    CREATE TABLE `services` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `name` varchar(255) NOT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

    ALTER TABLE services ADD UNIQUE `uq_services_name`(name);


    EBean entity
    Service.java:



    @Entity
    @Table(name = "services")
    public class Service extends BaseModel<Service> {
    public static Finder<Integer, Service> find = new Finder<>(Service.class);

    @Column(nullable = false, unique = true)
    private String name;

    // ... setters and getters

    }


    BaseModel.java:



    @MappedSuperclass
    public abstract class BaseModel<T> extends Model {

    @Id
    @Column
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    public final Integer getId() {
    return id;
    }

    @SuppressWarnings("unchecked")
    public final T setId(Integer id) {
    this.id = id;
    return (T) this;
    }
    }









    share|improve this question


























      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      I got a little issue here with a query for a string to search in DB for auto-complete functionality, the problem that I got that I need first results to be all statements that "Start" with then the statements that contain that string!



      For example: If I got the following records in a table in the database:





      1. Awesome service to provide

      2. Something else here

      3. Extra Service

      4. My Service is awesome

      5. Service Provided

      6. Zoo Services




      And I started to type "Service" I need No. 5 to show first, then the rest of items ( 1, 3, 4, 6)



      I know how to do that in MySQL, something like:



      select * from `services` where `name` like '%Service%' order by `name` like 'Service%' desc;


      Or maybe like the ways mentioned here: MySQL order by "best match"



      but I need to do that in Ebean.
      I tried:



      return Service.find.query().where().icontains("name", search).findList()


      But this return with 1, 3, 4, 5, 6,



      and now I do the following:



      final List<Service> list = Service.find.query().where()
      .istartsWith("name", search)
      .orderBy("name").findList(); // First query

      list.addAll(Service.find.query().where()
      .icontains("name", search)
      .not().istartsWith("name", search)
      .orderBy("name").findList()); // Then add the results for the second query
      return list;


      This will do the job, 5, 1, 3, 4, 6 but I don't like it, because I hit database with 2 queries, also I do exclude the first query in complex data type query in the second query, but anyway, is it a correct way? if not, do you have a suggestion or solution for a better way?



      Table:



      CREATE TABLE `services` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(255) NOT NULL,
      PRIMARY KEY (`id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

      ALTER TABLE services ADD UNIQUE `uq_services_name`(name);


      EBean entity
      Service.java:



      @Entity
      @Table(name = "services")
      public class Service extends BaseModel<Service> {
      public static Finder<Integer, Service> find = new Finder<>(Service.class);

      @Column(nullable = false, unique = true)
      private String name;

      // ... setters and getters

      }


      BaseModel.java:



      @MappedSuperclass
      public abstract class BaseModel<T> extends Model {

      @Id
      @Column
      @GeneratedValue(strategy = GenerationType.AUTO)
      private Integer id;

      public final Integer getId() {
      return id;
      }

      @SuppressWarnings("unchecked")
      public final T setId(Integer id) {
      this.id = id;
      return (T) this;
      }
      }









      share|improve this question















      I got a little issue here with a query for a string to search in DB for auto-complete functionality, the problem that I got that I need first results to be all statements that "Start" with then the statements that contain that string!



      For example: If I got the following records in a table in the database:





      1. Awesome service to provide

      2. Something else here

      3. Extra Service

      4. My Service is awesome

      5. Service Provided

      6. Zoo Services




      And I started to type "Service" I need No. 5 to show first, then the rest of items ( 1, 3, 4, 6)



      I know how to do that in MySQL, something like:



      select * from `services` where `name` like '%Service%' order by `name` like 'Service%' desc;


      Or maybe like the ways mentioned here: MySQL order by "best match"



      but I need to do that in Ebean.
      I tried:



      return Service.find.query().where().icontains("name", search).findList()


      But this return with 1, 3, 4, 5, 6,



      and now I do the following:



      final List<Service> list = Service.find.query().where()
      .istartsWith("name", search)
      .orderBy("name").findList(); // First query

      list.addAll(Service.find.query().where()
      .icontains("name", search)
      .not().istartsWith("name", search)
      .orderBy("name").findList()); // Then add the results for the second query
      return list;


      This will do the job, 5, 1, 3, 4, 6 but I don't like it, because I hit database with 2 queries, also I do exclude the first query in complex data type query in the second query, but anyway, is it a correct way? if not, do you have a suggestion or solution for a better way?



      Table:



      CREATE TABLE `services` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(255) NOT NULL,
      PRIMARY KEY (`id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

      ALTER TABLE services ADD UNIQUE `uq_services_name`(name);


      EBean entity
      Service.java:



      @Entity
      @Table(name = "services")
      public class Service extends BaseModel<Service> {
      public static Finder<Integer, Service> find = new Finder<>(Service.class);

      @Column(nullable = false, unique = true)
      private String name;

      // ... setters and getters

      }


      BaseModel.java:



      @MappedSuperclass
      public abstract class BaseModel<T> extends Model {

      @Id
      @Column
      @GeneratedValue(strategy = GenerationType.AUTO)
      private Integer id;

      public final Integer getId() {
      return id;
      }

      @SuppressWarnings("unchecked")
      public final T setId(Integer id) {
      this.id = id;
      return (T) this;
      }
      }






      java playframework ebean






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 19 at 9:22

























      asked Nov 18 at 10:09









      Al-Mothafar

      3,98634474




      3,98634474
























          1 Answer
          1






          active

          oldest

          votes

















          up vote
          0
          down vote













          Mothafar.



          That's a good question. I guess you don't like your solution because it queries the database twice. So what about querying first and then sorting afterwards:



          final List<Service> list = Service.find.query().where()
          .icontains("name", search)
          .findList()
          .sort(Comparator.comparingInt(service -> service.getName().indexOf(search)))
          );
          return list;


          This way #5 comes first and then the rest ordered by the appearance index of the search term. The caveat is that the sorting is not done through the database. But maybe it is possible to integrate such condition into the orderBy-clause.



          Cheers



          Jens






          share|improve this answer





















          • Thanks, but the problem with this that it will be really painful for a processor to handle this search over and over of each record, it is about 20K records, so it sounds like 2 queries ending with better performance than this, I think, am I right?
            – Al-Mothafar
            Nov 18 at 22:12










          • Alright. However, the sorting will be applied to the result set only. Will this have 20k records as well?
            – Jens.Huehn_at_SlideFab.com
            Nov 18 at 22:28










          • In the worst case, yes, in most cases, easier to hit around 10Ks, it is auto-complete so you can imagine how frequent will get hittings.
            – Al-Mothafar
            Nov 18 at 22:34










          • true, so for auto-complete maybe some kind of throttling makes sense: AJAX requests only every second instead of after every letter. Minimum length of 2 or maybe 3 letters and such things can help. This shouldn't hurt UX too much.
            – Jens.Huehn_at_SlideFab.com
            Nov 19 at 6:57











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














           

          draft saved


          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53359737%2febean-query-for-string-that-start-with-then-contains-a-specific-string%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          0
          down vote













          Mothafar.



          That's a good question. I guess you don't like your solution because it queries the database twice. So what about querying first and then sorting afterwards:



          final List<Service> list = Service.find.query().where()
          .icontains("name", search)
          .findList()
          .sort(Comparator.comparingInt(service -> service.getName().indexOf(search)))
          );
          return list;


          This way #5 comes first and then the rest ordered by the appearance index of the search term. The caveat is that the sorting is not done through the database. But maybe it is possible to integrate such condition into the orderBy-clause.



          Cheers



          Jens






          share|improve this answer





















          • Thanks, but the problem with this that it will be really painful for a processor to handle this search over and over of each record, it is about 20K records, so it sounds like 2 queries ending with better performance than this, I think, am I right?
            – Al-Mothafar
            Nov 18 at 22:12










          • Alright. However, the sorting will be applied to the result set only. Will this have 20k records as well?
            – Jens.Huehn_at_SlideFab.com
            Nov 18 at 22:28










          • In the worst case, yes, in most cases, easier to hit around 10Ks, it is auto-complete so you can imagine how frequent will get hittings.
            – Al-Mothafar
            Nov 18 at 22:34










          • true, so for auto-complete maybe some kind of throttling makes sense: AJAX requests only every second instead of after every letter. Minimum length of 2 or maybe 3 letters and such things can help. This shouldn't hurt UX too much.
            – Jens.Huehn_at_SlideFab.com
            Nov 19 at 6:57















          up vote
          0
          down vote













          Mothafar.



          That's a good question. I guess you don't like your solution because it queries the database twice. So what about querying first and then sorting afterwards:



          final List<Service> list = Service.find.query().where()
          .icontains("name", search)
          .findList()
          .sort(Comparator.comparingInt(service -> service.getName().indexOf(search)))
          );
          return list;


          This way #5 comes first and then the rest ordered by the appearance index of the search term. The caveat is that the sorting is not done through the database. But maybe it is possible to integrate such condition into the orderBy-clause.



          Cheers



          Jens






          share|improve this answer





















          • Thanks, but the problem with this that it will be really painful for a processor to handle this search over and over of each record, it is about 20K records, so it sounds like 2 queries ending with better performance than this, I think, am I right?
            – Al-Mothafar
            Nov 18 at 22:12










          • Alright. However, the sorting will be applied to the result set only. Will this have 20k records as well?
            – Jens.Huehn_at_SlideFab.com
            Nov 18 at 22:28










          • In the worst case, yes, in most cases, easier to hit around 10Ks, it is auto-complete so you can imagine how frequent will get hittings.
            – Al-Mothafar
            Nov 18 at 22:34










          • true, so for auto-complete maybe some kind of throttling makes sense: AJAX requests only every second instead of after every letter. Minimum length of 2 or maybe 3 letters and such things can help. This shouldn't hurt UX too much.
            – Jens.Huehn_at_SlideFab.com
            Nov 19 at 6:57













          up vote
          0
          down vote










          up vote
          0
          down vote









          Mothafar.



          That's a good question. I guess you don't like your solution because it queries the database twice. So what about querying first and then sorting afterwards:



          final List<Service> list = Service.find.query().where()
          .icontains("name", search)
          .findList()
          .sort(Comparator.comparingInt(service -> service.getName().indexOf(search)))
          );
          return list;


          This way #5 comes first and then the rest ordered by the appearance index of the search term. The caveat is that the sorting is not done through the database. But maybe it is possible to integrate such condition into the orderBy-clause.



          Cheers



          Jens






          share|improve this answer












          Mothafar.



          That's a good question. I guess you don't like your solution because it queries the database twice. So what about querying first and then sorting afterwards:



          final List<Service> list = Service.find.query().where()
          .icontains("name", search)
          .findList()
          .sort(Comparator.comparingInt(service -> service.getName().indexOf(search)))
          );
          return list;


          This way #5 comes first and then the rest ordered by the appearance index of the search term. The caveat is that the sorting is not done through the database. But maybe it is possible to integrate such condition into the orderBy-clause.



          Cheers



          Jens







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 18 at 21:18









          Jens.Huehn_at_SlideFab.com

          1225




          1225












          • Thanks, but the problem with this that it will be really painful for a processor to handle this search over and over of each record, it is about 20K records, so it sounds like 2 queries ending with better performance than this, I think, am I right?
            – Al-Mothafar
            Nov 18 at 22:12










          • Alright. However, the sorting will be applied to the result set only. Will this have 20k records as well?
            – Jens.Huehn_at_SlideFab.com
            Nov 18 at 22:28










          • In the worst case, yes, in most cases, easier to hit around 10Ks, it is auto-complete so you can imagine how frequent will get hittings.
            – Al-Mothafar
            Nov 18 at 22:34










          • true, so for auto-complete maybe some kind of throttling makes sense: AJAX requests only every second instead of after every letter. Minimum length of 2 or maybe 3 letters and such things can help. This shouldn't hurt UX too much.
            – Jens.Huehn_at_SlideFab.com
            Nov 19 at 6:57


















          • Thanks, but the problem with this that it will be really painful for a processor to handle this search over and over of each record, it is about 20K records, so it sounds like 2 queries ending with better performance than this, I think, am I right?
            – Al-Mothafar
            Nov 18 at 22:12










          • Alright. However, the sorting will be applied to the result set only. Will this have 20k records as well?
            – Jens.Huehn_at_SlideFab.com
            Nov 18 at 22:28










          • In the worst case, yes, in most cases, easier to hit around 10Ks, it is auto-complete so you can imagine how frequent will get hittings.
            – Al-Mothafar
            Nov 18 at 22:34










          • true, so for auto-complete maybe some kind of throttling makes sense: AJAX requests only every second instead of after every letter. Minimum length of 2 or maybe 3 letters and such things can help. This shouldn't hurt UX too much.
            – Jens.Huehn_at_SlideFab.com
            Nov 19 at 6:57
















          Thanks, but the problem with this that it will be really painful for a processor to handle this search over and over of each record, it is about 20K records, so it sounds like 2 queries ending with better performance than this, I think, am I right?
          – Al-Mothafar
          Nov 18 at 22:12




          Thanks, but the problem with this that it will be really painful for a processor to handle this search over and over of each record, it is about 20K records, so it sounds like 2 queries ending with better performance than this, I think, am I right?
          – Al-Mothafar
          Nov 18 at 22:12












          Alright. However, the sorting will be applied to the result set only. Will this have 20k records as well?
          – Jens.Huehn_at_SlideFab.com
          Nov 18 at 22:28




          Alright. However, the sorting will be applied to the result set only. Will this have 20k records as well?
          – Jens.Huehn_at_SlideFab.com
          Nov 18 at 22:28












          In the worst case, yes, in most cases, easier to hit around 10Ks, it is auto-complete so you can imagine how frequent will get hittings.
          – Al-Mothafar
          Nov 18 at 22:34




          In the worst case, yes, in most cases, easier to hit around 10Ks, it is auto-complete so you can imagine how frequent will get hittings.
          – Al-Mothafar
          Nov 18 at 22:34












          true, so for auto-complete maybe some kind of throttling makes sense: AJAX requests only every second instead of after every letter. Minimum length of 2 or maybe 3 letters and such things can help. This shouldn't hurt UX too much.
          – Jens.Huehn_at_SlideFab.com
          Nov 19 at 6:57




          true, so for auto-complete maybe some kind of throttling makes sense: AJAX requests only every second instead of after every letter. Minimum length of 2 or maybe 3 letters and such things can help. This shouldn't hurt UX too much.
          – Jens.Huehn_at_SlideFab.com
          Nov 19 at 6:57


















           

          draft saved


          draft discarded



















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53359737%2febean-query-for-string-that-start-with-then-contains-a-specific-string%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          "Incorrect syntax near the keyword 'ON'. (on update cascade, on delete cascade,)

          Alcedinidae

          Origin of the phrase “under your belt”?