 }
 
 extension QueryBuilder {
-    /// Applies a comparison filter to this query.
+    /// Applies a filter to this query for a joined entity. Usually you will use the filter operators to do this.
+    ///
+    ///     let users = try User.query(on: conn)
+    ///         .join(Pet.self, ...)
+    ///         .filter(Pet.self, \.type, .equals, .data("cat"))
+    ///         .all()
+    ///
+    /// - parameters:
+    ///     - joined: Joined model type to filter.
+    ///     - key: Swift `KeyPath` to a field on the model to filter.
+    ///     - type: Query filter type to use.
+    ///     - value: Value to filter by.
+    /// - returns: Query builder for chaining.
     @discardableResult
     public func filter<M, T>(_ joined: M.Type, _ key: KeyPath<M, T>, _ type: DatabaseQuery<M.Database>.FilterType, _ value: DatabaseQuery<M.Database>.FilterValue) throws -> Self
         where M: Fluent.Model, M.Database == Model.Database

        case group(GroupRelation, [Filter])
    }

    /// Defines a `Filter` that can be added on fetch, delete, and update operations to limit the set of data affected.
    public struct FilterItem {
        /// The field to filer.
        public var field: Database.QueryField

        /// The filter type.
        public var type: FilterType

        /// The filter value, possible another field.
        public var value: FilterValue

        /// Create a new filter.
        public init(field: Database.QueryField, type: FilterType, value: FilterValue) {
            self.field = field
            self.type = type

        }
    }

    /// Supported filter values.
    public struct FilterValue {
        enum QueryFilterValueStorage {
            case field(Database.QueryField)
