I have a model Item that has a name and description.I need to allow the user to search for a part of string in name or description.Instead of doing this using an sql query,I thought of using the search module that can be installed for playframework.
Looking at the documentation for search module ,I put these annotations to the model
#Entity
#Indexed
class Item{
#Field
public String name;
#Field
public String description;
public Date creationDate;
...
...
}
In application.conf ,I set
play.search.reindex=enabled
If I use an sql query like this
public static List<Item> getSearchResults(String kw){
List<Item> items = null;
if(kw!=null && kw.length()>0) {
String trimkw = kw.trim().toLowerCase();
String pattern = "%"+trimkw+"%";
String query="select distinct b from Item b where (lower(name) like :pattern or lower(description) like :pattern)";
items = Item.find(query).bind("pattern", pattern).fetch();
System.out.println("getSearchResults():: items="+items.size());
}
return items;
}
This works properly,and handles the cases where input string is uppercase or lowercase etc.Also it will get results for partial strings ..
For example ,
I have items JavaRing ,Android
when the kw="JAvA"
the search returns a list containing JavaRing
I tried using Search module like this
import play.modules.search.Search;
import play.modules.search.Query;
...
String qstr = "name:"+trimkw+" OR description:"+trimkw;
System.out.println("query string="+qstr);
Query q = Search.search(qstr, Item.class);
items = q.fetch();
System.out.println("items="+items.size());
But this returns an empty list for the same keyword as I used in the previous case.
keyword = "JAvA"
query string=name:java OR description:java
items=0
Is there something wrong with the way I have coded the search string?
Search module is based on Lucene. By default, Lucene searches for whole words. You didn't find anything because there isn't whole word 'java' in your fields.
Using wildcards, for instance name:java* OR description:java* you'll fit your needs. You can find more examples there
Updated link is http://lucene.apache.org/java/3_0_2/queryparsersyntax.html
In this case, if the keyword is to be found anywhere, I assume string pattern needs to be modified from % to *.
ie. String pattern = trimkw+"*";
The rest of the code could remain the same.
Related
I have a Couchbase-Document "Group" with a list of group-members-names. I want to query for all groups of one person. I managed to do it with N1QL ARRAY_CONTAINS - see in code example - but i hoped that i could generate the query from the method name as it is usual in Spring Data.
Any help is appreciated :)
I tried
public List<MyGroup> findAllByMembers(String member); and public List<MyGroup> findByMembers(String member); but they just return an empty list - i guess they try to match the whole "members" value and don't recognize it as a list -, no errors.
Code
My Document with a List field
#Data
#Document
public class MyGroup {
private String name;
private List<String> members = new ArrayList<>();
}
My Repository
#RepositoryDefinition(domainClass = MyGroup.class, idClass = String.class)
public interface MyGroupRepository extends CouchbaseRepository<MyGroup, String> {
//#Query("#{#n1ql.selectEntity} WHERE ARRAY_CONTAINS(members,$1) AND #{#n1ql.filter}")
public List<MyGroup> findAllByMembers(String member);
}
Expected
Given a "group1" with "member1" in members.
repository.findAllByMembers("member1"); should return ["group1"].
Couchbase is limited by the Spring Data specification. Unfortunately, we can't simply add new behaviors to it (if you switch to a relational database, it has to work with no breaking points). So, whenever you need to query something that has a N1QL specific function/keyword, you have to write a query via #Query
I can't wrap my head around how should i get my data without much boilerplate.
The problem:
I have a database that i cannot alter. Which has multiple field of same type almost same for example i have text_en and text_fr (both are the same word in different language English and French) and i got + 71 same field but different languages.
What I need is something like
#Entitiy(tableName = "blabla")
class X {
private String textTarget;
private String textMain;
...
}
How should I do my Dao interface to get desired language and map into x class
what should work is to update entity ColumnInfo(name ="text_en") for example.
#Query("select :main , :target from phrases where :id ")
List<X> getPhrase(String main,String target);
usage : getPhrase("text_en","text_esp");
// for example returning object X with field main = "hello" and target " holla")
The above example return the following error:
error: Not sure how to convert a Cursor to this method's return type
What you put in #Query is an SQL-statement, you can actually test them in sqlite command line utility or any desktop software to verify their correctness. So if you want a translation to the desired language, it should look like this:
#Query("SELECT :main AS text_main, :target AS text_target FROM `phrases` WHERE id = :id)
List<Translation> getTranslationById(String firstLang, String secondLang, long id);
Where Translation should be something like this:
class Translation {
#ColumnInfo("text_main")
String main;
#ColumnInfo("text_target")
String target;
//setters, getters, etc
}
This class is used only as a return value from the method.
I am using spring-sata-mongodb 1.8.2 with MongoRepository and I am trying to use the mongo $slice option to limit a list size when query, but I can't find this option in the mongorepository.
my classes look like this:
public class InnerField{
public String a;
public String b;
public int n;
}
#Document(collection="Record")
punlic class Record{
public ObjectId id;
public List<InnerField> fields;
public int numer;
}
As you can see I have one collection name "Record" and the document contains the InnerField. the InnerField list is growing all the time so i want to limit the number of the selected fields when I am querying.
I saw that: https://docs.mongodb.org/v3.0/tutorial/project-fields-from-query-results/
which is exactly what I need but I couldn't find the relevant reference in mongorepository.
Any ideas?
Providing an abstraction for the $slice operator in Query is still an open issue. Please vote for DATAMONGO-1230 and help us prioritize.
For now you still can fall back to using BasicQuery.
String qry = "{ \"_id\" : \"record-id\"}";
String fields = "{\"fields\": { \"$slice\": 2} }";
BasicQuery query = new BasicQuery(qry, fields);
Use slice functionality as provided in Java Mongo driver using projection as in below code.
For Example:
List<Entity> list = new ArrayList<Entity>();
// Return the last 10 weeks data only
FindIterable<Document> list = db.getDBCollection("COLLECTION").find()
.projection(Projections.fields(Projections.slice("count", -10)));
MongoCursor<Document> doc = list.iterator();
while(doc.hasNext()){
list.add(new Gson().fromJson(doc.next().toJson(), Entity.class));
}
The above query will fetch all documents of type Entity class and the "field" list of each Entity class document will have only last 10 records.
I found in unit test file (DATAMONGO-1457) way to use slice. Some thing like this.
newAggregation(
UserWithLikes.class,
match(new Criteria()),
project().and("likes").slice(2)
);
I want to run queries on my SQLite database that have been generated at runtime (instead of the standard compiletime queries in the #Dao). For example I might want to search a TEXT column in the SQLite db, to see if it contains all words in a list of N length. In raw SQLITE, a query where N is 3 would look like this :
SELECT * FROM table
WHERE textValue LIKE %queryTerm1%
AND textValue LIKE %queryTerm2%"
AND textValue LIKE %queryTerm3%"
I have tried generating, and passing the end of the query, instead of just passing variables. For example :
String generatedQuery = "textValue LIKE %queryTerm1% AND textValue LIKE %queryTerm2% AND textValue LIKE %queryTerm3%";
tableDao.find(generatedQuery);
and in the #Dao:
#Query("SELECT * FROM tableName WHERE :endQuery")
List<POJO> find(String endQuery);
This doesn't seem to work for me. Do you have any idea how to get runtime generated queries working with Room?
PS:
I have debugged the Dao implementation and looked at the statement it is running. This confirms that the generated query information, and the query are being passed correctly. I assume this is an issue with SQL injection prevention (aka more of an SQLITE problem, than a Room problem)
Update: latest release 1.1.1 of Room now uses SupportSQLiteQuery instead of String.
A query with typed bindings. It is better to use this API instead of
rawQuery(String, String[]) because it allows binding type safe
parameters.
New Answer:
#Dao
interface RawDao {
#RawQuery(observedEntities = User.class)
LiveData<List<User>> getUsers(SupportSQLiteQuery query);
}
Usage:
LiveData<List<User>> liveUsers = rawDao.getUsers( new
SimpleSQLiteQuery("SELECT * FROM User ORDER BY name DESC"));
Update your gradle to 1.1.1 (or whatever the current version is)
implementation 'android.arch.persistence.room:runtime:1.1.1'
implementation 'android.arch.lifecycle:extensions:1.1.1'
annotationProcessor "android.arch.persistence.room:compiler:1.1.1"
The problem is you want to pass a part of SQL statement, but Room treats it like a query parameter.
If you want you can try to use Kripton Persistence Library, an open source library written (by me :) ) that drastically simplify SQLite's management code for Android platform and support situations like this.
Kripton works with DAO pattern too, so concept are quite similar. Just to write an example that fit your needs:
Given a model class:
#BindType
public class User {
public long id;
public String name;
public String username;
public String email;
public Address address;
public String phone;
public String website;
public Company company;
}
a DAO definition:
#BindDao(User.class)
public interface UserDao {
#BindSqlInsert
void insert(User bean);
#BindSqlSelect
List<User> selectDynamic(#BindSqlDynamicWhere String where, #BindSqlDynamicWhereParams String[] args);
}
and a data source definition:
#BindDataSource(daoSet={UserDao.class}, fileName = "kripton.quickstart.db", generateAsyncTask = true)
public interface QuickStartDataSource {
}
Kripton will generate at compile time all code is need to work with database. So to accomplish your task with Kripton you have to write a code similar to:
BindQuickStartDataSource ds = BindQuickStartDataSource.instance();
// execute operation in a transaction
ds.execute(new BindQuickStartDataSource.SimpleTransaction() {
#Override
public boolean onExecute(BindQuickStartDaoFactory daoFactory) throws Throwable
{
UserDaoImpl dao = daoFactory.getUserDao();
String[] p={"hello"};
dao.selectDynamic("name=?",p);
return true;
}
});
In logcat when code above is executed you will see the generated log:
database OPEN READ_AND_WRITE_OPENED (connections: 1)
UserDaoImpl, selectDynamic (line 352): SELECT id, name, username, email, address, phone, website, company FROM user WHERE name=?
selectDynamic (line 357): ==> param0: 'hello'
Rows found: 0
database CLOSED (READ_AND_WRITE_OPENED) (connections: 0)
Kripton obviously supports static where conditions too and many other features (i start to develop it in 2015).
For more information about Kripton Persistence Library:
https://github.com/xcesco/kripton
http://abubusoft.com/
https://github.com/xcesco/kripton/wiki
I would like to create criteria or add restriction to my existing criteria (i think it has to be criteria) that will ignore "-" when searching for data's.
E.g I'm searching for number "888" and I would like to get "8-8-8" too.
I have bean that contains my number field
A.java
#Data
public class A {
[...]
#Length(max = 16)
#Column(length = 16)
private String number;
}
And here's my criteria
public Pair<Long, List<A>> filter(CompoundFilter filter, CompoundSort sort, int start, int count) {
Criteria criteria = getSession().createCriteria(A.class, "a_alias");
...
}
What should I add to criteria to achieve my goal?
My other idea is to create some hidden field (by hidden i mean the one that i wont use on UI, only fill with datas) that will hold "transformed" values and when filtering number i will filter on this field
try using regex ,the pattern would look like "[0-9]-[0-9]- ... [0-9]" , here instead of 0-9 build the pattern with your desired number. If i understood your question correctly then this could be an answer.