{"record":{"id":"5708b04994da3ec9","repo":"litedb-org/LiteDB","slug":"having-already-defined-in-this-query","errorCode":null,"errorMessage":"HAVING already defined in this query","messagePattern":"HAVING already defined in this query","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"LiteDB/Client/Database/LiteQueryable.cs","lineNumber":210,"sourceCode":"        /// </summary>\n        public ILiteQueryable<T> GroupBy(BsonExpression keySelector)\n        {\n            if (_query.GroupBy != null) throw new ArgumentException(\"GROUP BY already defined in this query\");\n\n            _query.GroupBy = keySelector;\n            return this;\n        }\n\n        #endregion\n\n        #region Having\n\n        /// <summary>\n        /// Filter documents after group by pipe according to predicate expression (requires GroupBy and support only one Having)\n        /// </summary>\n        public ILiteQueryable<T> Having(BsonExpression predicate)\n        {\n            if (_query.Having != null) throw new ArgumentException(\"HAVING already defined in this query\");\n\n            _query.Having = predicate;\n            return this;\n        }\n\n        #endregion\n\n        #region Select\n\n        /// <summary>\n        /// Transform input document into a new output document. Can be used with each document, group by or all source\n        /// </summary>\n        public ILiteQueryable<BsonDocument> Select(BsonExpression selector)\n        {\n            _query.Select = selector;\n\n            return new LiteQueryable<BsonDocument>(_engine, _mapper, _collection, _query);\n        }","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/litedb-org/LiteDB/blob/f906a5f850678719e39a39a006cb66dcae563cfa/LiteDB/Client/Database/LiteQueryable.cs#L192-L228","documentation":"Thrown by LiteQueryable.Having(BsonExpression) when _query.Having is already non-null. Like GroupBy, Having is stored as a single optional expression, so only one HAVING clause per query is supported. Having is intended to filter aggregated groups and must follow a GroupBy.","triggerScenarios":"Chaining two Having calls on the same query: col.Query().GroupBy(\"$.Category\").Having(\"$.sum > 10\").Having(\"$.count < 5\").","commonSituations":"Adding multiple post-aggregation filters by chaining (mimicking SQL AND semantics), or appending a Having from a filter-composition helper that runs more than once.","solutions":["Merge multiple predicates into one Having expression joined with AND, e.g. Having(\"$.sum > 10 AND $.count < 5\").","Build the combined predicate string once before calling Having.","If predicate parts come from optional inputs, concatenate only the non-null fragments."],"exampleFix":"// before\nvar q = col.Query()\n    .GroupBy(\"$.Category\")\n    .Having(\"$.sum > 10\")\n    .Having(\"$.count < 5\");\n\n// after\nvar q = col.Query()\n    .GroupBy(\"$.Category\")\n    .Having(\"$.sum > 10 AND $.count < 5\");","handlingStrategy":"validation","validationCode":"// Accumulate Having fragments and join with AND once.\nvar predicates = new List<string>();\nif (minSum.HasValue) predicates.Add($\"$.sum > {minSum}\");\nif (maxCount.HasValue) predicates.Add($\"$.count < {maxCount}\");\nif (predicates.Count > 0) q.Having(string.Join(\" AND \", predicates));","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Collect optional Having fragments in a list and join once.","Reserve Having for post-aggregation filters only."],"tags":["query","having","groupby","argument"],"backgroundTag":null,"analyzedSha":"f906a5f850678719e39a39a006cb66dcae563cfa","analyzedAt":"2026-08-13T21:56:30.148Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}