how to groupBY using spring data - spring

hi i'm using spring data in My project and I'm trying group by two fields, heres the request:
#Query( "SELECT obj from Agence obj GROUP BY obj.secteur.nomSecteur,obj.nomAgence" )
Iterable<Agence> getSecteurAgenceByPc();
but it doesnt work for me..what i want is this result:
-Safi
-CTM
CZC1448YZN
2UA13817KT
-Rabat
-CTM
CZC1349G1B
2UA0490SVR
-Agdal
G3M4NOJ
-Essaouira
-CTM
CZC1221B85
-Gare Routiere Municipale
CZC145YL3
What I get is
{
"status": 0,
"data":
[
{
"secteur": "Safi",
"agence": "CTM"
},
{
"secteur": "Safi",
"agence": "Dep"
},
{
"secteur": "Rabat",
"agence": "Agdal"
},
{
"secteur": "Rabat",
"agence": "CTM"
},
{
"secteur": "Essaouira",
"agence": "CTM"
},
{
"secteur": "Essaouira",
"agence": "Gare Routiere Municipale"
}
]
}

What you want is not possible with JPQL.
What does Group By do?
It combines all rows that are identical in the columns in the group by clause in to one row. Since it combines multiple rows into one, data in other columns can only be present in some combined fashion. For example, you can include MIN/MAX or AVG values, but never the orginal values.
Also the result with always be a table, never a tree.
Also note: there is no duplicated data. Every combination of secteur and agence appears exactly once.
If you want a tree structure, you have to write some java code for that.

Related

Match keys with sibling object JSONATA

I have an JSON object with the structure below. When looping over key_two I want to create a new object that I will return. The returned object should contain a title with the value from key_one's name where the id of key_one matches the current looped over node from key_two.
Both objects contain other keys that also will be included but the first step I can't figure out is how to grab data from a sibling object while looping and match it to the current value.
{
"key_one": [
{
"name": "some_cool_title",
"id": "value_one",
...
}
],
"key_two": [
{
"node": "value_one",
...
}
],
}
This is a good example of a 'join' operation (in SQL terms). JSONata supports this in a path expression. See https://docs.jsonata.org/path-operators#-context-variable-binding
So in your example, you could write:
key_one#$k1.key_two[node = $k1.id].{
"title": $k1.name
}
You can then add extra fields into the resulting object by referencing items from either of the original objects. E.g.:
key_one#$k1.key_two[node = $k1.id].{
"title": $k1.name,
"other_one": $k1.other_data,
"other_two": other_data
}
See https://try.jsonata.org/--2aRZvSL
I seem to have found a solution for this.
[key_two].$filter($$.key_one, function($v, $k){
$v.id = node
}).{"title": name ? name : id}
Gives:
[
{
"title": "value_one"
},
{
"title": "value_two"
},
{
"title": "value_three"
}
]
Leaving this here if someone have a similar issue in the future.

Sorting ElasticSearch query by multiple fields

I have some data that I'm trying to sort in a very specific order.
I've looked over a few questions here on SO and Elasticsearch sort on multiple queries was pretty helpful. From what I can tell I'm getting the data back in the correct order but it's not always the same data and appears to be very random as to what is returned from the query.
My question is, how do I get my data sorted correctly and get the expected data each time?
Example Data
[
{
id: 00,
...
current_outage: {
device_id: 00,
....
},
forecasted_outages: [
{
device_id: 00
}
]
},
{
id: 01,
...
current_outage: {
device_id: 01,
....
},
forecasted_outages: []
},
{
id: 02,
...
current_outage: null,
forecasted_outages: [
{
device_id: 02
}
]
},
{
id: 03,
...
current_outage: null,
forecasted_outages: []
},
]
Current Query
bool: {
should: [
{
constant_score: {
boost: 6,
filter: {
nested: {
path: 'current_outage',
query: {
exists: {
field: 'current_outage'
}
}
}
}
}
},
{
nested: {
path: 'forecasted_outages',
query: {
exists: {
field: 'forecasted_outages'
}
}
}
}
]
}
Just to reiterate, the above query returns the data in the format/sorted method I expect but it does NOT return the data that I expect each time. The returned data is very random as far as I can tell.
Sort Criteria:
First: Data with both current_outage and one or more forecasted_outages
Second: Data with only current_outage
Third: Data with only forecasted_outages
Edit
The data returning can be anything from zero to thousands of results depending on a user. The user has an option to paginate the data or return all of their relevant data.
Edit 2
The data returned will be anywhere from zero to 1,000 hits.
If the search hits is more than 10 (default result size) and all documents have same score (in your case it could be as you are provided constant score), then the data returned could be different for each run (giving randomness feeling).
The reason for this is, the search results are merged from different shards till the hit count reaches 10 and rest of the results are ignored. So every run can have different result based on the shards merged.
Increasing the result size to include all the search result can provide same data for every run.
UPDATE
Changing the Shard count to 1 might help (you have close and reopen the index if the index is already created).
PUT /twitter/_settings
{
"index" : {
"number_of_shards" : 1
}
}

MongoDb: how to search in multiple collections?

I got this structure in my mongodb (2 collections: restaurant and cocktail)
restaurant {id=1001, name="Res1", coor=[12.392, 19.123], cocktail=[13, 0, 92]}
cocktail {id=13, name="Capiroska"}, {id=167, name="Capirinha"}, {id=92, name="Negroni"}, {id=0, name="Martini"}
Multiple restaurants and multiple cocktails, N:N relationship.
My goal is to find which different cocktails I can drink within a specified area.
I've already written a query that finds all restaurants near my position like this:
mongoTemplate.find(new Query(Criteria.where("address.location").withinSphere(new Circle(latitude, longitude, radius/6371))
), Restaurant.class);
So that I obtain a list of restaurants.
Next steps are:
How to obtain distinct cocktail's id (no repetitions allowed)
How to look into cocktail collection in order to obtain all cocktail names
TY in advance!
This might not answer your question completely but can help
how to obtain distinct cocktails id (no repetitions allowed)
Your cocktail is in array so direct group or distinct might not work you can use $unwind.
What $unwind does is allow you to peel off a document for each element
and returns that resulting document
eg: for this object
{id=1001, name="Res1", coor=[12.392, 19.123], cocktail=[13, 0, 92]}
and this query
db.temp.aggregate( [ { $unwind: "$cocktail" } ] )
will result in
{ "_id" : 1001, "name" : "Res1", coor=[12.392, 19.123],, "cocktail" : 13 }
{ "_id" : 1001, "name" : "Res1", coor=[12.392, 19.123],, "cocktail" : 0 }
{ "_id" : 1001, "name" : "Res1", coor=[12.392, 19.123],, "cocktail" : 92 }
Now once you have all individual record you can group by cocktail
db.temp.aggregate( [ { $unwind: "$cocktail" },
{
"$group": {
_id: {
"_id": "$_id",
items: {$addToSet: '$cocktail'}}
}
}
}
] );
This should answer your 1st query
For getting cocktail names you need to use lookup, group and project something like this
db.temp.aggregate([
{
"$unwind": "$cocktail"
},
{
"$lookup": {
"from": "cocktail ",
"localField": "restaurant.cocktail._id",
"foreignField": "_id",
"as": "cocktails"
}
},
{ "$unwind": "$cocktails" },
{
"$group": {
"_id": "$_id",
"cocktail": { "$cocktail": "$cocktail" },
}
},
{
"$project": {
"name": 1,
"coor" : 1,
"cocktail.name" : 1,
}
}
]).pretty()
Note: This is just one approach, might not be the best way and also untested.
You can search data from two or more collection using join in MongoDB.
Depending on your scenario,the following links might help.
https://www.mongodb.com/blog/post/joins-and-other-aggregation-enhancements-coming-in-mongodb-3-2-part-1-of-3-introduction
what about using aggregation.
first perform match stage where you get all restaurant then perform unwind operation on cocktail after this you can perform group by on cocktail field. At this stage you have all unique cocktail id then perform lookup stage .
Order of stage
match
project if you want its optional
unwind
group
lookup
project //because you want only name of cocktail instead of complete
collection.
The code is in kotlin just convert it to java if you are using intellij as ide then it will convert it into java for you.
var match = Aggregation.match(Criteria.where("address.location").withinSphere(Circle(latitude, longitude, radius / 6371)))
var project = Aggregation.project("cocktail")
var unwind = Aggregation.unwind("cocktail")
var group = Aggregation.group("cocktail")
var lookup = Aggregation.lookup("your cocktail collection name","_id.cocktail","id","cocktailCollection")
var project1 = Aggregation.project("cocktailCollection.name").andExclude("_id")
var aggregation = Aggregation.newAggregation(match,project,unwind,group,lookup,project1)
println(aggregation) // if you want to see the query
var result = mongoTemplate.aggregate(aggregation,String::class.java)

is there any way where i can apply group and pagination using createQuery?

Query like this,
http://localhost:3030/dflowzdata?$skip=0&$group=uuid&$limit=2
and dflowzdata service contains data like,
[
{
"uuid": 123456,
"id": 1
},
{
"uuid": 123456,
"id": 2
},
{
"uuid": 7890,
"id": 3
},
{
"uuid": 123456,
"id": 4
},
{
"uuid": 4567,
"id": 5
}
]
Before Find Hook like,
if (query.$group !== undefined) {
let value = hook.params.query.$group
delete hook.params.query.$group
const query = hook.service.createQuery(hook.params.query);
hook.params.rethinkdb = query.group(value)
}
Its gives correct result but without pagination, like I need only two records but its give me all records
result is,
{"total":[{"group":"123456","reduction":3},{"group":"7890","reduction":1},{"group":"4567","reduction":3}],"data":[{"group":"123456","reduction":[{"uuid":"123456","id":1},{"uuid":"123456","id":2},{"uuid":"123456","id":4}]},{"group":"7890","reduction":[{"uuid":"7890","id":3}]},{"group":"4567","reduction":[{"uuid":"4567","id":5}]}],"limit":2,"skip":0}
can anyone help me how should get correct records using $limit?
According to the documentation on data types, ReQL commands called on GROUPED_DATA operate on each group individually. For more details, read the group documentation. So limit won't apply to the result of group.
The page for group tells: to operate on all the groups rather than operating on each group [...], you can use ungroup to turn a grouped stream or grouped data into an array of objects representing the groups.
Hence ungroup to apply functions to group's result:
r.db('db').table('table')
.group('uuid')
.ungroup()
.limit(2)

Count Unique Objects

My index looks like this:
"_source": {
"ProductName": "Random Product Name",
"Views": {
"Washington": [
{ "4nce5bbszjfppltvc": "2018-04-07T18:25:16.160Z" },
{ "4nce5bba8jfpowm4i": "2018-04-07T18:05:39.714Z" },
{ "4nce5bbszjfppltvc": "2018-04-07T18:36:23.928Z" },
]
}
}
I am trying to count the number of unique objects in Views.Washington.
In this case, the result would be 2, since two objects have the same key names. ( first and third object in the array ).
Obviously, my first thought was to use aggregations, but I am not sure how to use them with nested objects, like these.
Can this be done with normal aggregations?
Will I need to use a script?
Yes this can be done with Aggregations: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-nested-aggregation.html

Resources