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)
);
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 have a model object that looks like this:
#SuppressWarnings("serial")
#Entity
#Table(name = "selections")
public class Selection extends Model {
....
#ManyToMany
private Set<Market> markets;
....
}
Where Selection and Market both have id properties and static Finder<Long, *> find() methods.
And i'm trying to find all the Selection objects which contain a Market that's within a Set.
#Override #Transactional(readOnly = true) public List<Selection> findSelections(Set<Market> markets) {
// Query?
return Selection.find().where()...findList();
}
I know i can do something like:
return Selection.find().where().eq("markets.id", market.id).findList();
to find a single market object - but what about finding those objects from the Set? Without iterating over the Set?
return Selection.find().where().in("markets",markets).findList();
I have been struggling with the same problem, and after reading another SO question and the Ebean's Interface Query documentation I came out with this:
// Prepare the OQL query string
String oql = "find selection " +
"where markets.id in (:marketList) " +
"group by id " +
"having count(distinct markets.id) = :marketCount";
// Create the query
Query<Selection> query = Selection.find.setQuery(oql);
// Set the list of market IDs
List<Long> marketIds = Arrays.asList(1, 30, 9, 15, 6);
// Set query parameters (list of market IDs and how many they are)
query.setParameter("marketList", marketIds);
query.setParameter("marketCount", marketIds.size());
// Get the matching results
List<Selection> selections = query.findList();
I am using Play 2.4.2 with sbt-play-ebean plugin version 2.0.0, wich provides avaje-ebeanorm version 6.8.1.
For some extra functionality you might be interested in reading this question.
I am starting with hibernate search and am struggling with a query on a List<Integer>
I created a bridge to translate the list<Integer> to a string. From this, I am able to search by keyword exact matches on any item on the list, but I don't seem to be able to query it using range.
My entity A has an attribute "b" defined as List.
I would like to know if anyone can help me to get to query all the A entities which have any of the b elements inside a defined range?
For example:
an A instance with the following collection {1,10, 15}, should come up in the following queries on "b" attribute:
below(20),
above(14),
below(2)
but not in a search like:
above(16), below(0).
I hope I made myself clear.
Thanks in advance!
Change your bridge to storing same field multiple times, each with value a of the Integer list. So assuming your field is called myInt, you would store myInt = 1, myInt = 10 and myInt = 15, example code:
public class MyBridge implements FieldBridge {
public void set(String name, Object value, Document document, LuceneOptions luceneOptions) {
if (value instanceof List){
for(Object myInt:(List)value){
Field myIntField = new Field(name, myInt.toString(), luceneOptions.getStore(), luceneOptions.getIndex(), luceneOptions.getTermVector());
myIntField.setBoost(luceneOptions.getBoost());
document.add(myIntField);
}
}
}
}
Alternately, you might be able to plugin some custom lucene Filter to do it, but Filters are a bit convoluted.
I am using objectify-appengine framework for querying. Here is my simplified problem: Consider these 2 classes:-
public class Customer {
#Id private String email;
#Embedded private Account Account = new Account(); // note embedded annotation
}
and
public class Account {
private String number; //example: 1234
}
The following query works & gives me 1 customer:
Objectify ofy = ObjectifyService.begin();
ofy.query(Customer.class).filter("account.number = ", "1234");
Question:
However, if have a List of values (account numbers). Is there a way to fetch them in 1 query? I tried passing a list of account numbers like this:
ofy.query(Customer.class).filter("account.number = ", myAccountNumberList);
But if fails saying:
java.lang.IllegalArgumentException: A collection of values is not allowed.
Thoughts?
filter("account.number IN", theList)
Note that IN just causes the GAE SDK to issue multiple queries for you, merging the results:
The IN operator also performs multiple queries, one for each item in the specified list, with all other filters the same and the IN filter replaced with an EQUAL filter. The results are merged, in the order of the items in the list. If a query has more than one IN filter, it is performed as multiple queries, one for each possible combination of values in the IN lists.
From https://developers.google.com/appengine/docs/java/datastore/queries
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.