with one click
mongodb-filter-pattern
// MyBlog-specific pattern for extending read-side Mongo queries through GetBlogPostsQuery, GetBlogPostsHandler, IBlogPostRepository, and MongoDbBlogPostRepository using MongoDB.EntityFrameworkCore conventions.
// MyBlog-specific pattern for extending read-side Mongo queries through GetBlogPostsQuery, GetBlogPostsHandler, IBlogPostRepository, and MongoDbBlogPostRepository using MongoDB.EntityFrameworkCore conventions.
[HINT] Download the complete skill directory including SKILL.md and all related files
| name | mongodb-filter-pattern |
| confidence | medium |
| description | MyBlog-specific pattern for extending read-side Mongo queries through GetBlogPostsQuery, GetBlogPostsHandler, IBlogPostRepository, and MongoDbBlogPostRepository using MongoDB.EntityFrameworkCore conventions. |
The imported filter skill assumed raw Mongo driver filters, paginated API
endpoints, and repository methods that return Result<T>. MyBlog's current read
path is different: GetBlogPostsQuery calls GetBlogPostsHandler, which reads
through IBlogPostRepository / MongoDbBlogPostRepository, then caches DTOs in
memory and Redis.
This skill defines the filter pattern that actually fits MyBlog.
| Layer | Canonical file | Owner | Current behavior |
|---|---|---|---|
| Query contract | src/Web/Features/BlogPosts/List/GetBlogPostsQuery.cs | Sam | Query has no filter properties yet. |
| Handler | src/Web/Features/BlogPosts/List/GetBlogPostsHandler.cs | Sam | Uses a fixed cache key blog:all; maps domain entities to DTOs. |
| Repository contract | src/Domain/Interfaces/IBlogPostRepository.cs | Sam | GetAllAsync(CancellationToken) returns domain entities directly. |
| Repository implementation | src/Web/Data/MongoDbBlogPostRepository.cs | Sam | Uses EF Core LINQ over BlogDbContext, ordered by CreatedAt descending. |
| Unit tests | tests/Unit.Tests/Handlers/GetBlogPostsHandlerTests.cs | Gimli | Verifies cache hit/miss behavior and repository calls. |
| Integration tests | tests/Integration.Tests/BlogPosts/MongoDbBlogPostRepositoryTests.cs | Gimli | Verifies ordering, persistence, delete, and concurrency behavior against real Mongo. |
Query contract first.
Repositories return domain entities, not Result<T>.
Result wrapping in handlers.Use EF Core LINQ, not Builders<T>.Filter, for normal MyBlog queries.
MongoDbBlogPostRepository is built on BlogDbContext.AsNoTracking(), then add conditional Where(...) clauses.Cache keys must include filter state.
blog:all only fits the unfiltered list.Handler + repository + tests move together.
public sealed record GetBlogPostsQuery(
string? SearchTerm = null,
string? Author = null,
bool? IsPublished = null) : IRequest<Result<IReadOnlyList<BlogPostDto>>>;
Rules:
Task<IReadOnlyList<BlogPost>> GetAllAsync(
string? searchTerm = null,
string? author = null,
bool? isPublished = null,
CancellationToken ct = default);
Rules:
src/Domain/Interfaces and the implementation in
src/Web/Data.await using var ctx = await contextFactory.CreateDbContextAsync(ct);
var query = ctx.BlogPosts.AsNoTracking();
if (!string.IsNullOrWhiteSpace(searchTerm))
{
var term = searchTerm.Trim();
query = query.Where(p =>
p.Title.Contains(term) ||
p.Content.Contains(term) ||
p.Author.Contains(term));
}
if (!string.IsNullOrWhiteSpace(author))
{
var normalizedAuthor = author.Trim();
query = query.Where(p => p.Author == normalizedAuthor);
}
if (isPublished is not null)
{
query = query.Where(p => p.IsPublished == isPublished.Value);
}
return await query
.OrderByDescending(p => p.CreatedAt)
.ToListAsync(ct);
Rules:
AsNoTracking() for list reads.private static string BuildCacheKey(GetBlogPostsQuery request)
{
var search = request.SearchTerm?.Trim() ?? string.Empty;
var author = request.Author?.Trim() ?? string.Empty;
var published = request.IsPublished?.ToString() ?? "all";
return $"blog:list:{search}:{author}:{published}";
}
Rules:
Update GetBlogPostsHandlerTests to cover:
Add/extend MongoDbBlogPostRepositoryTests to prove:
Current MyBlog state:
Web.csproj does not currently reference FluentValidation.Rule:
The imported skill included several patterns that are not current MyBlog conventions:
Builders<T>.Filter + BsonRegularExpression examples — MyBlog uses the EF
Core adapter first.IEndpointRouteBuilder list endpoints.Result<T> — current repositories return
domain entities and leave result wrapping to handlers.If MyBlog later exposes REST endpoints for blog lists, revisit this skill and promote only the pieces that map to the new code path.
src/Web/Features/BlogPosts/List/GetBlogPostsQuery.cssrc/Web/Features/BlogPosts/List/GetBlogPostsHandler.cssrc/Domain/Interfaces/IBlogPostRepository.cssrc/Web/Data/MongoDbBlogPostRepository.cstests/Unit.Tests/Handlers/GetBlogPostsHandlerTests.cstests/Integration.Tests/BlogPosts/MongoDbBlogPostRepositoryTests.cssrc/Web/Features/BlogPosts/List/GetBlogPostsQuery.cssrc/Web/Features/BlogPosts/List/GetBlogPostsHandler.cssrc/Domain/Interfaces/IBlogPostRepository.cssrc/Web/Data/MongoDbBlogPostRepository.cstests/Unit.Tests/Handlers/GetBlogPostsHandlerTests.cstests/Integration.Tests/BlogPosts/MongoDbBlogPostRepositoryTests.cs