Elasticsearch running aggregate guery - products bought by clients who only buy that product - sql

My docs represents an order in the given format:
{
"name", // the client
"sku" // the product
}
So, suppose the follow data exists:
{ "name": "rudolph", "sku": "apple" }
{ "name": "rudolph", "sku": "apple" }
{ "name": "rudolph", "sku": "apple" }
{ "name": "john", "sku": "banana" }
{ "name": "john", "sku": "banana" }
{ "name": "paul", "sku": "banana" }
{ "name": "paul", "sku": "apple" }
{ "name": "peter", "sku": "banana" }
I can get the clients who bought only 1 kind of item with the query:
{
"aggs": {
"clients": {
"terms": {
"field": "name"
},
"aggs": {
"distinct_sku": {
"cardinality": {
"field": "sku"
}
},
"unique_sku": {
"bucket_selector": {
"buckets_path": {
"qty": "distinct_sku"
},
"script": "params.qty == 1"
}
},
"aggs": {
"terms": {
"field": "sku"
}
}
}
}
},
"size": 0
}
which results
{
...
"aggregations": {
"clients": {
...
"buckets": [
{
"key": "rudolph",
"doc_count": 3,
...
"aggs": {
...
"buckets": [
{
"key": "apple",
"doc_count": 3
}
]
}
},
{
"key": "john",
"doc_count": 2,
...
"aggs": {
...
"buckets": [
{
"key": "banana",
"doc_count": 2
}
]
}
},
{
"key": "peter",
"doc_count": 1,
...
"aggs": {
...
"buckets": [
{
"key": "banana",
"doc_count": 1
}
]
}
}
]
}
}
}
It's possible to manage the query to return how much each item appears in the result?
Something like this:
{
"apple" : 1,
"banana" : 2
}
Thanks in advance.
EDIT
My base has a huge amount of clients and a small quantity of products, so:
Iterate over the above aggregation result to build the wanted result is not an option.
If I have to send a query for each product, It's Ok.

Related

How to apply filter for nested arrays in mulesoft dataWeave

I tried to filter below json payload characters[] array which is having result as 'valid' and data[] array name as 'WBB' and priority as '1'
I tried below code but not working can some one help me ?.
flatten(payload.offers.category.characters) filter ((item, index) -> item.result=='valid' and flatten(item.data) filter ((item, index) -> item.name=='WBB' and item.priority==1))
Json payload
{
"offers": [
{
"id": 100,
"name": "Test1",
"category": {
"characters": [
{
"result": "valid",
"data": [
{
"name": "WBB",
"priority": 1
},
{
"name": "ILL",
"priority": 2
}
]
}
]
}
},
{
"id": 200,
"name": "Test2",
"category": {
"characters": [
{
"data": [
{
"name": "ISS",
"priority": 1
},
{
"name": "ILL",
"priority": 2
}
]
}
]
}
},
{
"id": 300,
"name": "Test3",
"category": {
"characters": [
{
"data": [
{
"name": "WSS",
"priority": 1
},
{
"name": "ILL",
"priority": 2
}
]
}
]
}
}
]
}
Expected payload
[
{
"name": "WBB",
"priority": 1
}
]
flatten((flatten(payload.offers..characters) filter $.result == "valid").data) filter ($.name=="WBB" and $.priority == 1)
flatten(payload..data) filter ((item, index) -> item.name == 'WBB' )

Grouping Response Data

I am trying to get data from my database but when I show and make it become api response, I have some problem for grouping it based on productid.
I have response data that created based on golang like this:
[
{
"product_id": "1",
"product_name": "Cardigan",
"pitems": [
{
"id": "625ad1bc-66c5-440e-a527-d029d401ec2b",
"name": "Box",
"qty": 1
},
{
"id": "625ad1bc-66c6-440e-a527-d029d401ec2b",
"name": "test items1",
"qty": 1
},
{
"id": "625ad1bc-66c7-440e-a527-d029d401ec2b",
"name": "test items2",
"qty": 1
},
{
"id": "625ad1bc-66c8-440e-a527-d029d401ec2b",
"name": "test items3",
"qty": 1
}
]
},
{
"product_id": "2",
"product_name": "Polo",
"product_sku": "P01",
"items": [
{
"id": "625ad1bc-66c5-440e-a527-d029d401ec2b",
"name": "Box",
"qty": 1
},
{
"id": "625ad1bc-66c6-440e-a527-d029d401ec2b",
"name": "test items1",
"qty": 1
},
{
"id": "625ad1bc-66c7-440e-a527-d029d401ec2b",
"name": "test items2",
"qty": 1
},
{
"id": "625ad1bc-66c8-440e-a527-d029d401ec2b",
"name": "test items3",
"qty": 1
}
]
}
]
But This response is not my expected result, my expected result is like:
[
{
"product_id": "1",
"product_name": "Cardigan",
"pitems": [
{
"id": "625ad1bc-66c5-440e-a527-d029d401ec2b",
"name": "Box",
"qty": 1
},
{
"id": "625ad1bc-66c6-440e-a527-d029d401ec2b",
"name": "test items1",
"qty": 1
},
{
"id": "625ad1bc-66c7-440e-a527-d029d401ec2b",
"name": "test items2",
"qty": 1
}
]
},
{
"product_id": "2",
"product_name": "Polo",
"product_sku": "P01",
"items": [
{
"id": "625ad1bc-66c8-440e-a527-d029d401ec2b",
"name": "test items3",
"qty": 1
}
]
}
]
Can Anyone help me to solve my problem?
What does it mean to show detailed data?
the easy way is:
create 2 func like this:
func detail(id int)(result model.Struct)
{ return result }
func product()(result model.Struct_Result) {
for data.Next() {
// call func detail
data.Scan(&id, &product)
detailResult := detail(id)
// then put together with struct and mix append ()
outputLoop := model.Result{
"product_id": id,
"pitems": [
{
"id": detailResult.id,
"name": detailResult.name,
"qty": detailResult.qty
},
]
}
result = append(result,outputLoop)
}
return result
}

Mongo DB query: project array element to property

Having following data
{
"_id": "...",
"name": "John",
"purchases": [
{
"date": {
"$date": "2016-12-20T00:00:00.000Z"
},
"amount": 1000
},
{
"date": {
"$date": "2016-12-23T00:00:00.000Z"
},
"amount": 100
}
]
}
How to get latest purchase amount as result field with different name?
To get next result:
{
"_id": "...",
"name": "John",
"purchases": [
{
"date": {
"$date": "2016-12-20T00:00:00.000Z"
},
"amount": 1000
},
{
"date": {
"$date": "2016-12-23T00:00:00.000Z"
},
"amount": 100
}
]
},
"latestPurchaseAmount": 100
}
You have to use the $rename take a look at this link
And for your last item you should look at this it will helps you Link
You can do something like this. This below query will unwind all the purchases in the collection and, sort the purchases by date descending and, limit the result to one and project the corresponding amount.
db.purchases.aggregate([{
$unwind: "$purchases"
}, {
$sort: {
"purchases.date": -1
}
}, {
$limit: 1
}, {
$project: {
_id: 0,
latestPurchaseAmount: "$purchases.amount"
}
}]);
Output
{ "latestPurchaseAmount" : 100 }

ElasticSearch combine match and function score queries

I have a complicated query to run in elasticsearch that spans across multiple fields (nested and non-nested). I am using a bool should query across a multi-field match and nested field match.
Additionally I want a composite scoring which takes into account several other parameters such as location, rating etc.
I tried to run a simplified proof of concept combined query which looks for a matching term and tries to use function score for the other fields but I am running into an error from es.
GET init/restaurant/_search/
{
"query": {
"match": {
"cuisine_categories": "Oriental"
},
"function_score": {
"functions": [
{
"gauss": {
"coordinates": {
"origin": { "lat": 74.20, "lon": 31.23 },
"offset": "1km",
"scale": "3km"
}
}
},
{
"gauss": {
"nomnom_rating": {
"origin": "4.5",
"offset": "0.5",
"scale": "1"
}
},
"weight": 2
},
{
"gauss": {
"estimated_preparation_time": {
"origin": "30",
"offset": "10",
"scale": "20"
}
},
"weight": 5
}
]
}
}
}
The query is not a valid. The match clause should be within the query object of function score as shown below
Example:
POST init/restaurant/_search/
{
"query": {
"function_score": {
"functions": [
{
"gauss": {
"coordinates": {
"origin": {
"lat": 74.2,
"lon": 31.23
},
"offset": "1km",
"scale": "3km"
}
}
},
{
"gauss": {
"nomnom_rating": {
"origin": "4.5",
"offset": "0.5",
"scale": "1"
}
},
"weight": 2
},
{
"gauss": {
"estimated_preparation_time": {
"origin": "30",
"offset": "10",
"scale": "20"
}
},
"weight": 5
}
],
"query": {
"match": {
"cuisine_categories": "Oriental"
}
}
}
}
}

Need to get the following query to output correctly

Hi guys I've been trying all day to construct this simple mongo query but I can't get the desire output. Below is the query and the current output.
db.customers.aggregate(
{ $match : { "status" : "Closed" } },
{ $unwind: "$lines" },
{ $group : {
_id:{label: "$lines.label",date: {$substr: [ "$date", 0, 10 ]}},
values: { $push: { date: {$substr: [ "$date", 0, 10 ]}} },
count: { $sum: 1 }
}},
{ $project : {
_id : 1,
values:1,
count:1
}}
);
Which outputs the following.
{
"result": [
{
"_id": {
"label": "label",
"date": "2010-10-01"
},
"values": [
{
"date": "2010-10-01"
},
{
"date": "2010-10-01"
},
{
"date": "2010-10-01"
},
{
"date": "2010-10-01"
}
],
"count": 4
},
{
"_id": {
"label": "label",
"date": "2010-10-10"
},
"values": [
{
"date": "2010-10-10"
}
],
"count": 1
},
{
"_id": {
"label": "label",
"date": "2010-07-25"
},
"values": [
{
"date": "2010-07-25"
}
],
"count": 1
}
]
}
However the output below is the one that I'm looking for and just can't get. I can obviously get all the data I desire, just in the wrong places.
{
"result": [
{
"_id": "label",
"values": [
{
"date": "2010-11-27",
"count": 4
},
{
"date": "2010-10-10",
"count": 1
},
{
"date": "2010-07-25",
"count": 1
}
]
}
]
}
Like always thanks for the help and support.
Can you try this:
db.customers.aggregate([
{ $match : { "status" : "Closed" } },
{ $unwind: "$lines" },
{ $group : {
_id:{label: "$lines.label",date: {$substr: [ "$date", 0, 10 ]}},
values: { $push: { date: {$substr: [ "$date", 0, 10 ]}} },
count: { $sum: 1 }
}},
// This one I added to group them behind a single label in an array list
{ $group : {
_id:{
label: "$_id.label"
},
values : {
$push : { date : "$date", count : "$count" }
}
}
},
{ $project : {
_id : 1,
values:1,
count:1
}
}
]);
If I got your problem right, you like to group the counts + dates in an values array. That you can do with $push after the 1st group stage.