I'm new in spring and I have this situation..
This is my Json.
{
"_id": {
"$oid": "60ba776d3ef89419f8668333"
},
"reference": "20210906164455",
"transactionReference": "999999999999",
"status": "PARTIALLY",
"currency": "BRL",
"amount": {
"$numberDecimal": "99.80"
},
"ucode": "XXXXXXXXXXXXXXXXXXX",
"refunds": [
{
"_id": {
"$oid": "60ba77f03ef89419f8668337"
},
"currency": "BRL",
"amount": {
"$numberDecimal": "1.10"
},
"status": "PARTIALLY",
"createDate": {
"$date": "2021-06-04T18:58:57.145Z"
}
},
{
"_id": {
"$oid": "60ba7b6d3ef89419f8668339"
},
"currency": "BRL",
"amount": {
"$numberDecimal": "10.10"
},
"status": "PARTIALLY",
"createDate": {
"$date": "2021-06-04T19:13:49.229Z"
}
}
],
"confirmed": true,
"createDate": {
"$date": "2021-09-01T00:56:45.235Z"
},
"lastModifiedDate": {
"$date": "2021-09-04T19:15:57.787Z"
},
"amountRefunded": {
"$numberDecimal": "21.30"
}
}
I made this query
db.collection.aggregate([
{
"$addFields": {
"refunds": {
"$concatArrays": [
"$refunds",
[
{
"amount": "$amount",
"createDate": "$createDate"
}
]
]
}
}
},
{
"$unwind": {
"path": "$refunds"
}
},
{
"$replaceRoot": {
"newRoot": {
"$mergeObjects": [
"$$ROOT",
"$refunds"
]
}
}
},
{
"$unset": [
"refunds"
]
},
{
"$sort": {
"createDate": -1
}
},
{
"$limit": 10
}
])
And now I have two objects like I would like. Pratical example
So now I need to transfer this code to Java using Aggregation.
I made this implementation but the problem is... I'm losting the other values and only the values inside of array refunds appears.
AggregationOperation match = Aggregation.match(criteria);
AggregationOperation unwind = Aggregation.unwind("refunds");
AggregationOperation sort = Aggregation.sort(Sort.Direction.DESC, "createDate");
AggregationOperation replaceRoot = Aggregation.replaceRoot("refunds");
AggregationOperation limit = Aggregation.limit(20);
Aggregation aggregation = Aggregation.newAggregation(match, unwind, sort, replaceRoot, limit);
List<Payments> paymentRefunds = mongoTemplate.aggregate(aggregation, mongoTemplate.getCollectionName(Payments.class), Payments.class).getMappedResults();
How can I reply the Mongo query to Aggregation?
So... I solved the problem with the code below!
AggregationOperation match = Aggregation.match(criteria);
AggregationOperation unwind = new UnwindOperation(Fields.field(refunds),true);
AggregationOperation sort = Aggregation.sort(Sort.Direction.DESC, createDate);
AggregationOperation limit = Aggregation.limit(request.getRows());
AggregationOperation replaceRoot = ReplaceRootOperation.builder().withDocument(new Document("$mergeObjects", Arrays.asList(Aggregation.ROOT, "$refunds")));
AggregationOperation addFieldAndConcatArrays = aoc -> new Document("$addFields", new Document(refunds, ArrayOperators.ConcatArrays.arrayOf(List.of(new Document(amount, "$amount"))).concat("$refunds").toDocument(aoc)));
AggregationOperation unset = aoc -> new Document("$unset", refunds);
Aggregation aggregation = Aggregation.newAggregation(match, addFieldAndConcatArrays, unwind, replaceRoot, unset, sort, limit);
return mongoTemplate.aggregate(aggregation, Payment.class, Payment.class).getMappedResults();
Related
I have a collection which name called 'airport' and i have Atlas Auto Complete index you can see JSON config below.
{
"mappings": {
"dynamic": false,
"fields": {
"name": [
{
"type": "string"
},
{
"foldDiacritics": false,
"maxGrams": 7,
"minGrams": 2,
"type": "autocomplete"
}
]
}
}
}
and this is my Document record
{
"_id": {
"$oid": "63de588c7154cc3ee5cbabb2"
},
"name": "Antalya Airport",
"code": "AYT",
"country": "TR",
"createdDate": {
"$date": {
"$numberLong": "1675516044323"
}
},
"updatedDate": {
"$date": {
"$numberLong": "1675516044323"
}
},
"updatedBy": "VISITOR",
"createdBy": "VISITOR",
}
And This is my MongoDB Query
public List<Document> autoCompleteAirports(AutoCompleteRequest autoCompleteRequest) {
return database.getCollection(AIRPORT).aggregate(
Arrays.asList(new Document("$search",
new Document("index", "airportAutoCompleteIndex")
.append("text",
new Document("query", autoCompleteRequest.getKeyword())
.append("path", "name")
)))
).into(new ArrayList<>());
}
So, when i type "antalya" or "Antalya", this works. But when i type "Antaly" or "antal" there is no result.
Any solution ?
i tried change min and max grams settings on index
I have the below aggregation query which i need to translate into java
Below aggregation query needs to be translated into java using elastic search client RestHighLevelCleint
not sure i tried multiple times but the java code is not able to translate as per the below query.
{
"aggs": {
"recommendations": {
"nested": {
"path": "events.recommendationData"
},
"aggs": {
"exception": {
"filter": {
"terms": {
"events.recommendationData.exceptionId": [
"2"
]
}
},
"aggs": {
"exceptionIds": {
"terms": {
"field": "events.recommendationData.exceptionId.keyword",
"size": 10
},
"aggs": {
"recommendations": {
"nested": {
"path": "events.recommendationData.recommendations"
},
"aggs": {
"recommendationType": {
"terms": {
"field": "events.recommendationData.recommendations.recommendationType",
"size": 10
}
}
}
}
}
}
}
}
}
}
}
}
using the below code with RestHighLevelClient
AggregationBuilder recommendations =
AggregationBuilders.nested("recommendations", "events.recommendationData");
AggregationBuilder exception = AggregationBuilders
.filter("exception", QueryBuilders.termsQuery("events.recommendationData.exceptionId", "2"));
AggregationBuilder exceptionIds = AggregationBuilders.terms("exceptionIds")
.field("events.recommendationData.exceptionId.keyword").size(10);
AggregationBuilder recommendations2 =
AggregationBuilders.nested("recommendations", "events.recommendationData.recommendations");
AggregationBuilder recommendationType = AggregationBuilders.terms("recommendationType")
.field("events.recommendationData.recommendations.recommendationType").size(10);
AggregationBuilder build =
recommendations
.subAggregation(exception)
.subAggregation(exceptionIds)
.subAggregation(recommendations2)
.subAggregation(recommendationType);
and it is producing the wrong query as i posted below which is not working.
{
"aggregations": {
"recommendations": {
"nested": {
"path": "events.recommendationData"
},
"aggregations": {
"exception": {
"filter": {
"terms": {
"events.recommendationData.exceptionId": [
"1",
"2"
],
"boost": 1
}
}
},
"exceptionIds": {
"terms": {
"field": "events.recommendationData.exceptionId.keyword",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
}
},
"recommendations": {
"nested": {
"path": "events.recommendationData.recommendations"
}
},
"recommendationType": {
"terms": {
"field": "events.recommendationData.recommendations.recommendationType",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
}
}
}
}
}
}
Expected: Every aggregation is a sub aggregation to the previous.
Therefore, if you see the expected query, recommendationType is sub-aggregation of recommendations2. These together are sub-aggregation to exceptionIds and so on. Therefore only one line needs to change here, which is instead of
AggregationBuilder build =
recommendations
.subAggregation(exception)
.subAggregation(exceptionIds)
.subAggregation(recommendations2)
.subAggregation(recommendationType);
use this,
recommendations.subAggregation(
exception.subAggregation(
exceptionIds.subAggregation(
recommendations2.subAggregation(recommendationType)
)
)
);
currently I implemented it from postman but I can't implement it from JAVA code. Below is the post json body.
I only want to have the full-text search for Innovation. And groupby email and orderby score. But seems the sum of the score still didn't work. Who can help me out? It worked now.
{
"from": 0,
"size": 10,
"query": {
"bool": {
"must": [
{
"query_string": {
"query": "Innovation"
}
}
]
}
},
"highlight": {
"require_field_match": false,
"pre_tags" : [ "<b>" ],
"post_tags" : [ "</b>" ],
"order" : "score",
"highlight_filter" : false,
"fields": {
"*": {}
}
},
"aggs": {
"group_by_emails": {
"terms": { "field": "email" }
}
}
}
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.from(0);
searchSourceBuilder.size(10);
searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
QueryStringQueryBuilder queryString = new QueryStringQueryBuilder(keyword);
searchSourceBuilder.query(queryString);
Script script = new Script("_score;");
AggregationBuilder aggregation = AggregationBuilders
.terms("agg")
.field("email")
.order(BucketOrder.aggregation("sum_score", false))
.subAggregation(AggregationBuilders.sum("sum_score").script(script))
;
searchSourceBuilder.aggregation(aggregation);
System.out.println(searchSourceBuilder.toString());
SearchRequest searchRequest = new SearchRequest(indexName);
searchRequest.source(searchSourceBuilder);
I have the following data structure
[{
"id": "1c7bbebd-bc3d-4352-9ac0-98c01d13189d",
"version": 0,
"groups": [
{
"internalName": "Admin group",
"fields": [
{
"internalName": "Is verified",
"uiProperties": {
"isShow": true
}
},
{
"internalName": "Hide",
"uiProperties": {
"isHide": false
}
},
...
]
},
...
]
},
{
"id": "2b7bbebd-bc3d-4352-9ac0-98c01d13189d",
"version": 0,
"groups": [
{
"internalName": "User group",
"fields": [
{
"internalName": "Is verified",
"uiProperties": {
"isShow": true
}
},
{
"internalName": "Blocked",
"uiProperties": {
"isBlocked": true
}
},
...
]
},
...
]
},
...
]
Internal names of the fields can be repeated. I want to group by group.field.internalName and cut the array(for pagination) and get the output like:
{
"totalCount": 3,
"items": [
{
"internalName": "Blocked"
},
{
"internalName": "Hide"
},
{
"internalName": "Is verified"
}
]}
I wrote a query that works,
db.layouts.aggregate(
{
$unwind : "$groups"
},
{
$unwind : "$groups.fields"
},
{
$group: {
"_id" : {
"internalName" : "$groups.fields.internalName",
},
"internalName" : {
$first : "$groups.fields.internalName"
}
}
},
{
$group: {
"_id" : null,
"items" : {
$push : "$$ROOT"
},
"totalCount" : {
$sum : 1
}
}
},
{
$project: {
"items" : {
$slice : [ "$items", 0, 20 ]
},
"totalCount": 1
}
})
but I have the problem of translating it to java api. Notice that i need to use mongoTemplate approach. Here is what i have and where i'm struck
final List<AggregationOperation> aggregationOperations = new ArrayList<>();
aggregationOperations.add(unwind("groups"));
aggregationOperations.add(unwind("groups.fields"));
aggregationOperations.add(
group("groups.fields.internalName")
.first("groups.fields.internalName").as("internalName")
);
aggregationOperations.add(
group()
.push("$$ROOT").as("fields")
.sum("1").as("totalCount") // ERROR only string ref can be placed, but i need a number?
);
aggregationOperations.add(
project()
.andInclude("totalCount")
.and("fields").slice(size, page * size)
);
final Aggregation aggregation = newAggregation(aggregationOperations);
mongoTemplate.aggregate(aggregation, LAYOUTS, FieldLites.class).getMappedResults()
With this query i have the problem with sum(), because i can place only a String ref by api(but need a number) and with project operation - got an exception
java.lang.IllegalArgumentException: Invalid reference 'totalCount'!] with root cause
Can you help me with this query translation?
You can use count
group()
.push("$$ROOT").as("fields")
.count().as("totalCount")
I am trying to build ElasticSearch query using java API. This query uses stored_fields, can anyone please help me how to build stored_field query from java code.
{
"from": 0,
"size": 10,
"stored_fields": [
"f1",
"f2",
"f3",
"f4"
],
"query": {
"bool": {
"must": {
"match": {
"compositeField1": {
"query": "test123",
"type": "boolean",
"operator": "AND"
}
}
}
},
"sort": [
{
"_score": {}
}
]
}
Code following
SearchRequestBuilder srb = ....
srb.setFrom(0).setSize(10).storedFields("f1", "f2", "f3", "f4");
srb.addSort(SortBuilders.scoreSort());
BoolQueryBuilder bqb = new BoolQueryBuilder();
bqb.must(QueryBuilders.matchQuery("compositeField1", "test123")
.operator(Operator.AND).type(MatchQuery.Type.BOOLEAN));
srb.setQuery(bqb);
Note: ES set some default required parameters.