For now the only solution I have is with query duplication:

(
  (sum(kafka_consumergroup_lag[1d]) by (consumergroup) >= 100)
  * on(consumergroup) group_left(team)
  catalog_entities_info
)
or ignoring(team) (sum(kafka_consumergroup_lag[1d]) by (consumergroup) >= 100)

First half will add team label where possible, and second or half will add missed data (important to merge vectors while ignoring added team label, otherwise we will have duplicates).

Answer from aiven on Stack Overflow
🌐
Prometheus
prometheus.io › docs › prometheus › latest › querying › operators
Operators | Prometheus
Many-to-one and one-to-many matchings refer to the case where each vector element on the "one"-side can match with multiple elements on the "many"-side. This has to be explicitly requested using the group_left or group_right modifiers, where left/right determines which vector has the higher cardinality.
🌐
Webscale
webscale.com › home › blog › prometheus querying – breaking down promql
PromQL Querying: group_left, Joins, and Working Examples
June 8, 2026 - These keywords convert the match ... has the higher cardinality. So a group_left means that multiple series on the left side can match a single series on the right....
People also ask

What is PromQL?
PromQL (Prometheus Query Language) is the query language built into Prometheus for selecting, filtering, and aggregating time series data. You use it to write expressions that power dashboards, alerts, and ad-hoc metric analysis.
🌐
last9.io
last9.io › blog › promql-cheat-sheet
PromQL Cheat Sheet: Queries, Functions, and Labels | Last9
How do I filter by label values in PromQL?
Use curly brace selectors: http_requests_total{job="api", status="500"} for exact matches, {status=~"5.."} for regex matches, and {status!="200"} to exclude a value. Multiple label filters combine with AND logic.
🌐
last9.io
last9.io › blog › promql-cheat-sheet
PromQL Cheat Sheet: Queries, Functions, and Labels | Last9
How do I predict future resource usage in PromQL?
Use predict_linear(metric[window], seconds). For example, predict_linear(node_filesystem_free_bytes[30d], 86400 7) predicts disk space 7 days from now based on the last 30-day trend. Use a long lookback window for more stable predictions.
🌐
last9.io
last9.io › blog › promql-cheat-sheet
PromQL Cheat Sheet: Queries, Functions, and Labels | Last9
🌐
Iximiuz
iximiuz.com › en › posts › prometheus-vector-matching
Prometheus Cheat Sheet - How to Join Multiple Metrics (Vector Matching)
November 30, 2021 - How to join metrics on matching labels? Vector matching: one-to-one, one-to-many and many-to-one, many-to-many. What on/ignoring clause is for? group_left and group_right explained. Logical/set operations explained.
🌐
Robust Perception
robustperception.io › left-joins-in-promql
Left joins in PromQL – Robust Perception | Prometheus Monitoring Experts
December 30, 2019 - This gives us inner one-to-one joins with PromQL, but not left joins. We've also only got the matching labels in the result. We've previously looked at how to do some of this: a * on (foo, bar) group_left(baz) b · which is equivalent to ·
🌐
Chris's Wiki
utcc.utoronto.ca › ~cks › space › blog › sysadmin › PrometheusGroupLeftAndRightNotes
Prometheus's group_left() and group_right() operators
December 17, 2023 - With group_left() this is the right side, and with group_right() it's the left side. In theory this sounds symmetric, but in practice it's not, because if you're forced to use group_right(), by itself your alert labels won't come from the metric whose value generated the alert.
🌐
Robust Perception
robustperception.io › using-group_left-to-calculate-label-proportions
Using group_left to calculate label proportions – Robust Perception | Prometheus Monitoring Experts
This is where group_left comes in. It says that for each set of matching labels, many time series on the left hand side can match with just one time series on the right hand side.
🌐
Last9
last9.io › blog › promql-cheat-sheet
PromQL Cheat Sheet: Queries, Functions, and Labels | Last9
September 12, 2024 - group_left() allows the left-hand side series to have multiple time series for each matching label. group_right() does the same for the right-hand side series. ... This query joins the up metric with the http_requests_total metric on the instance ...
Find elsewhere
🌐
Grafana
grafana.com › blog › 2021 › 08 › 04 › how-to-use-promql-joins-for-more-effective-queries-of-prometheus-metrics-at-scale
How to use PromQL joins for more effective queries of Prometheus metrics at scale | Grafana Labs
August 5, 2021 - Run a single rule per metric that uses a PromQL join to inject the appropriate reference label into the generated series. ... groups: - name: slo_metric expr: count(api_response_latency{labelone="xyz", labeltwo="abc"} > 100) labels: reference_label: xyzabc ... This file would be collected by Grafana Agent. Then the following rule group could be used in Cortex: ... groups: - name: slo_metric expr: count by (reference_label) ((api_response_latency * on (labelone,labeltwo) group_left(reference_label) sli_info > 100)
🌐
Promlabs
promlabs.com › promql-cheat-sheet
PromLabs | PromQL Cheat Sheet
Go get our self-paced in-depth PromQL training! Select latest sample for series with a given metric name: ... Available aggregation operators: sum(), min(), max(), avg(), stddev(), stdvar(), count(), count_values(), group(), bottomk(), topk(), quantile() ... Only keep series from the left-hand side whose sample values are larger than their right-hand-side matches:
Top answer
1 of 3
76

You can use the argument list of group_left to include extra labels from the right operand (parentheses and indents for clarity):

(
  max(consul_health_service_status{status="critical"}) 
  by (service_name,status,node) == 1
)
   + on(service_name,node) group_left(env)
(
   0 * consul_service_tags
)

The important part here is the operation + on(service_name,node) group_left(env):

  • the + is "abused" as a join operator (fine since 0 * consul_service_tags always has the value 0)
  • group_left(env) is the modifier that includes the extra label env from the right (consul_service_tags)
2 of 3
15

It is a good practice in Prometheus ecosystem to expose additional labels, which can be joined to multiple metrics, via a separate info-like metric as explained in this article. For example, consul_service_tags metric exposes a set of tags, which can be joined to metrics via (service_name, node) labels.

The join is usually performed via on() and group_left() modifiers applied to * operation. The * doesn't modify values for time series on the left side because info-like metrics usually have constant 1 values. The on() modifier is used for limiting the labels used for finding matching time series on the left and the right side of *. The group_left() modifier is used for adding additional labels from time series on the right side of *. See these docs for details.

For example, the following PromQL query adds env label from consul_service_tags metric to consul_health_service_status metric with the same set of (service_name, node) labels:

consul_health_service_status
  * on(service_name, node) group_left(env)
consul_service_tags

Additional label filters can be added to consul_health_service_status if needed. For example, the following query returns only time series with status="critical" label:

consul_health_service_status{status="critical"}
  * on(service_name, node) group_left(env)
consul_service_tags
🌐
Last9
last9.io › blog › prometheus-group-by-label
Prometheus Group By Label: Advanced Aggregation Techniques for Monitoring | Last9
June 12, 2026 - How to use group by in PromQL? Place the by clause after an aggregation function like sum(), avg(), or count(). For example: ... This aggregates the metric and groups results by service and region. What is the difference between group_left and group_right in Prometheus?
🌐
Medium
medium.com › @amimahloof › the-group-left-or-right-is-just-the-promql-way-of-working-with-data-that-has-multiple-elements-on-8e683f2f2c91
The group left or right is just the promQL way of working with data that has multiple elements on… | by Ami Mahloof | Medium
October 28, 2018 - so if you start your query then the results for that will be on the left (left side of the query) on the right side of the query, there are other results. PromQL does the join based on cardinality — you just need to determine what extra data ...
🌐
Stack Overflow
stackoverflow.com › questions › 74287092 › promql-join-a-metric-with-a-group-left-with-another-metric-resticted-by-a-boolea
PromQL join a metric with a group left with another metric resticted by a boolean condition - Stack Overflow
The above query returns mi timeseries joined with m2 but "> xxxx" is applied to value of m1 instead of reducing the set of m2 timeseries This could be a syntax m1 > on(...) group left (m2 > xxxx) but, obviously I get a parse error · promql · Share · Improve this question ·
🌐
SigNoz
signoz.io › guides › how can i 'join' two metrics in a prometheus query? - joining metrics in promql
How can I 'join' two metrics in a Prometheus query? - Joining Metrics in PromQL | SigNoz
July 24, 2024 - PromQL doesn't have explicit inner and outer join operations. Instead, it uses vector matching with modifiers like group_left and group_right to achieve similar results.
🌐
Grafana
grafana.com › blog › promql-vector-matching-what-it-is-and-how-it-affects-your-prometheus-queries
PromQL vector matching: what it is and how it affects your Prometheus queries | Grafana Labs
December 14, 2024 - Since we have queried all the interesting Pokémons on the left side, we can also use sum to get the sum across the series. Now both sides have no labels, so Prometheus can match them. However, what if we wanted to create a chart of the percentages of Pokémon types we caught? Using grouping on the aggregation makes us go back to square one: Creating multiple charts or using Grafana variables is also not an option if we want to, for example, compare that data on a single plot. Fortunately, PromQL ...
🌐
Google Groups
groups.google.com › g › prometheus-users › c › po4YEDU5uWw
Promql JOIN many-to-many matching
October 6, 2021 - Where it's more typical is to do joins between *pods* and *nodes*, because each pod is running on a node. There is an N:1 relationship between pod and node, and that lets you do a group_left or group_right join.