How do I convert this to mongodb aggregate query? - sql

SELECT prop_type , count(prop_type) As no_of_properties
from prop_type
JOIN prop_for_rent USING (prop_type)
GROUP BY prop_type;
prop_type and prop_for_rent are both tables. Then "prop_type" used for the JOIN and GROUP BY is an attribute name in both.
The expected result is for the query to count the number of properties in each property type.
And this is the result of the sql version of it
Screenshot of sql query result
So i need it to display the same prop_type and then the number of properties in each type in mongodb

db.prop_type.aggregate([
{
"$lookup": {
"from": "prop_for_rent",
"localField": "prop_type",
"foreignField": "prop_type",
"as": "prop_for_rent_docs"
}
},
{
"$unwind": {
path: "$prop_for_rent_docs",
preserveNullAndEmptyArrays: true
}
},
{
"$group": {
"_id": "$prop_type",
"no_of_properties": {
"$sum": 1
}
}
}
])
mongoplayground

Related

SQL having equivalent keyword in ES query DSL

I have the following query to be converted to DSL and executed on ES. I could not find a suitable aggregation and filter over results of aggregation available out-of-the-box in ES. As an alternative, I am fetching the 'group by count' for each id from ES and filtering the result as a part of my application logic, which is not efficient. Can you suggest any more suitable solution?
select distinct id from index where colA = "something" group by id having count(*) > 10;
index mapping
id : (string)
colA: (string)
Terms aggregation: to get distinct Ids.
Bucket selector: to return ids with doc count more than 10
{
"query": {
"bool": {
"filter": [
{
"term": {
"colA.keyword": "something" --> where clause
}
}
]
}
},
"aggs": {
"distinct_id": {
"terms": { --> group by
"field": "id.keyword",
"size": 10
},
"aggs": {
"ids_having_count_morethan_10": {
"bucket_selector": { --> having
"buckets_path": {
"count": "_count"
},
"script": "params.count>10"
}
}
}
}
}
}

how to select value if key is uuid in mongodb

the mongodb data like this:
{
"_id": "123dsadasfa454sdsaw",
"hashmap": {
"uuid-12sadsadw5": {
"name": "bob"
},
"uuid-12sadsadwew5": {
"name": "alice"
}
},
"age": 10
}
"hashmap" like java HashMap, the key is uuid like "uuid-12sadsadwew5" and the value is object.
I want to get the data which the name in "hashmap" value is not null. And I use sql :
db.tabl1.find({"hashmap.values.name":{$ne:null}})
but cannot get the right result
You can use this aggregation query:
First use $objectToArray to create an array with values k and v. As we don't know the key (k) we can search by value (v).
Then $unwind array
And $match values where name is not null.
And then regroup and recreate the object using $arrayToObject.
db.collection.aggregate([
{
"$set": {
"hashmap": {
"$objectToArray": "$hashmap"
}
}
},
{
"$unwind": "$hashmap"
},
{
"$match": {
"hashmap.v.name": {
"$ne": null
}
}
},
{
"$group": {
"_id": "$_id",
"hashmap": {
"$push": "$hashmap"
}
}
},
{
"$set": {
"hashmap": {
"$arrayToObject": "$hashmap"
}
}
}
])
Example here

Postgres/JSON Updating nested array elements

Given the input JSON from the 'table' under a column named '_value'. I would like to replace the field "sc" as text from object to value of name under sc.
The json before updating looks like this.
{
"iProps": [
{
"value": {
"rules": [
{
"ao": {
"sc": {
"web_link": "abc.com",
"name": "name"
}
}
},
{
"ao": {
"sc": ""
}
}
]
}
}
]
}
The json after updating should look like this.
{
"iProps": [
{
"value": {
"rules": [
{
"ao": {
"sc": "name"
}
},
{
"ao": {
"sc": ""
}
}
]
}
}
]
}
I tried the below query to get to 'rules' array but having difficulty to proceed further in parsing and updating.
WITH values AS (
SELECT iprop -> 'value' -> 'rules' AS value FROM
table t,jsonb_array_elements(t._value->'iProps') AS
iprop )
SELECT *
from values, jsonb_array_elements(values.ao)
throws following error
ERROR: column values.ao does not exist
LINE 26: from values, jsonb_array_elements(values.ao)
^
SQL state: 42703
Character: 1396
You can try below mentioned query considering your structure is constant and the data type of your column is JSONB.
with cte as (
select
vals2->'ao'->'sc'->'name' as namevalue,
('{iProps,'||index1-1||',value,rules,'||index2-1||',ao,sc}')::text[] as json_path
from
table_,
jsonb_array_elements(value_->'iProps')
with ordinality arr1(vals1,index1),
jsonb_array_elements(vals1->'value'->'rules')
with ordinality arr2(vals2,index2)
)
update table_
set value_ = jsonb_set(value_,cte.json_path,cte.namevalue,false)
from cte
WHERE cte.namevalue IS NOT NULL
DEMO

How to realize sum(field) group by multi field in elasticsearch?

I'm using logstash to save row data from MySQL to ElasticSearch. How to calculate sum on one field group by two fields?
For example, here is one table named "Students", it has several columns: id, class_id, name, gender, age;
and here is one SQL query:
select class_id, gender, sum(age) from Students group by class_id, gender;
How to translate this SQL to ElasticSearch high level rest client API call?
Below is my try, but it is not correct:
public TermsAggregationBuilder constructAggregation() {
TermsAggregationBuilder aggregation = AggregationBuilders.terms("by_classid")
.field("classId.keyword");
aggregation = aggregation.subAggregation(AggregationBuilders.terms("by_gender").field("gender.keyword"));
aggregation = aggregation.subAggregation(AggregationBuilders.sum("sum_age")
.field("age"));
return aggregation;
}
Following is the raw query for your sql statement
POST aggregation_index_2/_search
{
"size": 0,
"aggs": {
"gender_agg": {
"terms": {
"field": "gender"
},
"aggs": {
"class_id_aggregator": {
"terms": {
"aggs": {
"field": "class_id"
},
"age_sum_aggregator": {
"sum": {
"field": "age"
}
}
}
}
}
}
}
}
Mappings
PUT aggregation_index_2
{
"mappings": {
"properties": {
"gender": {
"type": "keyword"
},
"age": {
"type": "integer"
},
"class_id": {
"type": "integer"
}
}
}
}

Elastic search aggregation

Is there a way to return only one product if it has different color.
e.g. suppose I have a product with following properties:
brand,color,title
nike, red, air max
nike, blue, air max
now I want to create elastic search query to return only one product while aggregation but count as two belonging to brand nike.
{
"query" : {
"match_all" : {}
},
"aggs" : {
"brand" : {
"terms" : {
"field" : "brand"
},
"aggs" : {
"size" : {
"terms" : {
"field" : "title"
}
}
}
}
}
}
I am not able to get desired results. I want like select name,color,title, count(*) title from product group by name,title
I think you want to get document, aggregated by name,title
This can be done using topHits aggregation.
{
"size": 0,
"query": {
"match_all": {}
},
"aggs": {
"brand": {
"terms": {
"field": "name"
},
"aggs": {
"size": {
"terms": {
"field": "title"
}
},
"aggs":{
"top_hits" :{
"_source" :[ "name","color","band"],
"size":1
}
}
}
}
}
}
For count, there is always doc_count in returned buckets.
Hope this helps!! If I am missing something, do mention.
Thanks