spring data mongodb NearQuery add another criteria - spring

Is it possible to add a Criteria to a NearQuery?
Currently I am doing this:
public List<UserLocation> getUserNearLocation(Point p, double min, double max){
NearQuery query = NearQuery.near(p).minDistance(new Distance(min, Metrics.KILOMETERS)).maxDistance(new Distance(max, Metrics.KILOMETERS));
GeoResults<UserLocation> results = mongoTemplate.geoNear(query, UserLocation.class);
List<UserLocation> all = new ArrayList<UserLocation>();
Iterator<GeoResult<UserLocation>> iter = results.iterator();
while (iter.hasNext()){
GeoResult<UserLocation> temp = iter.next();
all.add(temp.getContent());
}
return all;
}
I would like to add another criteria to the query, is it possible and how?

just add an additional query like shown below.
NearQuery query = NearQuery.near(new Point(1, 2)).query(Query.query(Criteria.where("foo").is("bar")));

Related

spring data mongodb BulkOperations upsert not save the data to mongodb

for (int i = 0; i < deviceDataList.size(); i++) {
updateList = new ArrayList<>();
deviceData = deviceDataList.get(i);
Query query = new Query();
query.addCriteria(new Criteria("seqId").is(deviceData.getDeviceCd()));
query.addCriteria(new Criteria("time").is(deviceData.getGpsAtMillis()));
Update update = new Update();
update.set("seqId", deviceData.getSeqId());
update.set("partId", deviceData.getPartId());
update.set("partName", deviceData.getPartName());
update.set("time", deviceData.getTime());
Pair<Query, Update> updatePair = Pair.of(query, update);
updateList.add(updatePair);
}
MongoTemplate mongoTemplate = null;
BulkOperations operations = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, collectionName);
operations.upsert(updateList);
BulkWriteResult writeResult = operations.execute();
result.setSuccess(writeResult.wasAcknowledged());
result.setResult(writeResult.getModifiedCount());
I write a code to insert data when data do not exist or update data when data exist, but I find when the update data is included, the updateList data does not save into the MongoDB, I did not know why, this confuse me.
I use MongoDB 3.4.12 and use the spring-data-MongoDB jar, I am not sure why this happens, and what I should do to solve this problem.

ES Match query analogue in Lucene

I use queries like this one to run in ES:
boolQuery.must(QueryBuilders.matchQuery("field", value).minimumShouldMatch("50%"))
What's the straight analogue for this query in Lucene?
Match Query, as I understand it, basically analyzes the query, and creates a BooleanQuery out of all the terms the analyzer finds. You could get sorta close by just passing the text through QueryParser.
But you could replicate it something like this:
public static Query makeMatchQuery (String fieldname, String value) throws IOException {
//get a builder to start adding clauses to.
BooleanQuery.Builder qbuilder = new BooleanQuery.Builder();
//We need to analyze that value, and get a tokenstream to read terms from
Analyzer analyzer = new StandardAnalyzer();
TokenStream stream = analyzer.tokenStream(fieldname, new StringReader(value));
stream.reset();
//Iterate the token stream, and add them all to our query
int countTerms = 0;
while(stream.incrementToken()) {
countTerms++;
Query termQuery = new TermQuery(new Term(
fieldname,
stream.getAttribute(CharTermAttribute.class).toString()));
qbuilder.add(termQuery, BooleanClause.Occur.SHOULD);
}
stream.close();
analyzer.close();
//The min should match is a count of clauses, not a percentage. So for 50%, count/2
qbuilder.setMinimumNumberShouldMatch(countTerms / 2);
Query finalQuery = qbuilder.build();
return finalQuery;
}

Spring MongoDB query with or operator and text search

How can i build this MongoDB query with Spring Criteria?
{
$or: [
{ "$text" : { "$search" : "570-11024" } },
{"productDetails.code": "572-R110"}
]
}
It combines a fulltext index search with normal Where criteria with an orOperator.
Query's orOperator(Criteria... criteria) method takes only Criteria and no TextCriteria and also no CriteriaDefinition interface.
Yeah you are right, in spring data mongo you could do this,
final TextCriteria textCriteria = TextCriteria.forDefaultLanguage().matchingAny("570-11024");
final DBObject tc = textCriteria.getCriteriaObject();
final Criteria criteria = Criteria.where("productDetails.code").is("572-R110");
final DBObject co = criteria.getCriteriaObject();
BasicDBList or = new BasicDBList();
or.add(tc);
or.add(co);
DBObject qq = new BasicDBObject("$or", or);
// Use MongoTemplate to execute command
mongoTemplate.executeCommand(qq);
Yes, you currently cannot use the Query's orOperator method to combine Criteria and TextCriteria. A workaround involves converting both the Criteria and TextCriteria objects to its Document representations, adding it to a BasicDbList and then converting back to a "$or" Criteria object.
TextCriteria textCriteria = TextCriteria.forDefaultLanguage().matchingAny("570-11024");
Criteria criteria = Criteria.where("productDetails.code").is("572-R110");
BasicDBList bsonList = new BasicDBList();
bsonList.add(criteria.getCriteriaObject());
bsonList.add(textCriteria.getCriteriaObject());
Query query = new Query();
query.addCriteria(new Criteria("$or").is(bsonList));
mongoTemplate.find(query, YourEntity.class);
PS: Someone has raised this issue in the spring-data-mongodb repo with a proposed fix by
changing the parameter types of orOperator from Criteria to CriteriaDefinition.
https://github.com/spring-projects/spring-data-mongodb/issues/3895.

matchAllQuery() in ElasticSearch

matchAllQuery() in Elasticsearch gets me only 10 results how do I increase its output so that I can get as many results as per my requirement.
Code
QueryBuilder query = QueryBuilders.matchAllQuery();
By default 10 results are returned, you need to increase the size parameter:
SearchRequestBuilder request = client.prepareSearch(index)
.setQuery(QueryBuilders.matchAllQuery())
.setSize(100);
Yes u can do , here you can pass aPageRequestcount whatever you want and If you want no of records exist in Elastic search than repository.count() will work for that :-
int aPageRequestcount = (int) repository.count();
NativeSearchQueryBuilder aNativeSearchQueryBuilder = new NativeSearchQueryBuilder();
aNativeSearchQueryBuilder.withIndices(indexName).withTypes(type).withPageable(new PageRequest(0, aPageRequestcount));
final BoolQueryBuilder aQuery = new BoolQueryBuilder();
NativeSearchQuery nativeSearchQuery = aNativeSearchQueryBuilder.withQuery(aQuery).build();
= elasticsearchTemplate.queryForList(nativeSearchQuery, A.class);

LINQ to SQL . how to select all record using .take()

var result=(from refridgerators in context.A
group refridgerators by new { refridgerators.Id, refridgerators.Name } into gr
select new DAO<String>
{
Key = gr.Key.Name,
Count = gr.Count()
}).OrderByDescending(k => k.Count).Take(numberOfRecords).ToList();
This is my linq to sql query this is working perfectly fine.
this shows top 5 records (sorted by their count) if i pass numberOfRecords =5.
now my problem is i don`t want to modify query. so what should i do in above query to show all records. This is in relation with my requirement i want to use same query to show all refridgerators and Top 5 , top 10 refridgerators.
I am not sure if it is possible using LINQ. but i guess there must be something related to this.
I would simply don't add the Take to the query but to the code where you consume this query.
So for example:
public static IEnumerable<DAO> GetRefrigerators()
{
var query = from refridgerators in context.A
group refridgerators by new { refridgerators.Id, refridgerators.Name } into gr
select new DAO<String>
{
Key = gr.Key.Name,
Count = gr.Count()
};
return query.OrderByDescending(k => k.Count);
}
Now you can either use:
var refrigerators = GetRefrigerators().Take(5).ToList();
or
var refrigerators = GetRefrigerators().Take(10).ToList();
or
var refrigerators = GetRefrigerators().ToList();
I'd make numberOfRecords a int? and if the value is null you should not call Take(numberOfRecords)
var result = (from refridgerators in context.A
group refridgerators by new { refridgerators.Id, refridgerators.Name } into gr
select new DAO<String>
{
Key = gr.Key.Name,
Count = gr.Count()
}).OrderByDescending(k => k.Count);
if(numberOfRecords.HasValue)
result = result.Take(numberOfRecords.Value);
return result.ToList();
I know it changes your query a little bit but I believe it is pretty acceptable, adding a numberOfRecords of a super high value adds an overheard to your query which isn't useful in your case.
So this post is very old, I know, but my solution is not provided (maybe someone wants to achieve the same after 2 years, like me):
You could create your own extension-method that also works with linq 2 sql. Example:
public static class LinqExtensions
{
public static IEnumerable<TResult> TakeIfNotNull<TResult>(this IEnumerable<TResult> source, int? count)
{
return !count.HasValue ? source : source.Take(count.Value);
}
}
this takes an int? instead of int and returns either the source-enumerable if count is null else it returns the result of default Take-method.
So you could write like:
.OrderByDescending(k => k.Count).TakeIfNotNull(numberOfRecords).ToList();
if numberOfCounts is null, it'll take all records.
As the right solution has already been posted by Tim, still I want your attention to the simpler solution, if suits to your requirement.
Add one more if condition at the top of this query.
if(allRecordRequired)
{
numberOfRecords = 2000000;
}
Leave your query as it is.
Pass a huge number to your method.A number that is equal (at least) or bigger than the items count.That should give you all records.

Resources