RavenDB LINQ查询问题:如何实现输入与文档集合的交集查询
问题描述
我在数据库中定义了如下Element实体:
public class Element { public string Id { get; set; } = string.Empty; public IEnumerable<string> ExternalIds { get; set; } = Enumerable.Empty<string>(); ... }
为查询拥有至少一个匹配ExternalId的Element文档,我创建了如下扇出索引:
public class Elements_ByExternalIds : AbstractIndexCreationTask<Element> { public class Result { public string? ExternalId { get; set; } public string? ElementId { get; set; } } public Elements_ByExternalIds() { Map = elements => from element in elements from externalId in element.ExternalIds select new Result { ExternalId = externalId, ElementId = element.Id }; } }
我需要在仓储中实现查询:传入一组externalIds,返回自身ExternalIds集合包含其中任意值的Element文档(输入与文档集合交集非空)。我尝试了两种查询写法:
public async Task<Result<IEnumerable<Element>>> GetElementsWhichContainExternalIds(IEnumerable<string> externalIds) { try { var elements = await _session .Query<Elements_ByExternalIds.Result, Elements_ByExternalIds>() .Where(element => externalIds.Contains(element.externalId)) // 第一次尝试 //.Where(element => externalIds.Any(externalId => externalId == element.ExternalId)) // 第二次尝试 .Select(elements => new Elements_ByExternalIds.Result() { ExternalIds = elements.ExternalIds, ElementId = elements.ElementId }) .ToListAsync(cancellationToken); return Result.Success(elements); } catch (Exception ex) { return Result.Failure<IEnumerable<Element>>($"Failed {ex.Message}"); } }
但两种写法均报错:
Could not understand expression
请问如何在RavenDB索引中执行交集查询,其中一个集合来自应用输入,另一个在RavenDB文档中?我的思路是创建扇出索引,尝试匹配索引单个值与闭包集合。
解决方案
1. 修正自定义索引的查询逻辑
你的查询报错有两个核心原因:一是索引结果类Result中不存在ExternalIds属性,却在Select中试图访问;二是闭包集合的匹配语法需要调整。修正后的代码如下:
public async Task<Result<IEnumerable<Element>>> GetElementsWhichContainExternalIds(IEnumerable<string> externalIds, CancellationToken cancellationToken) { try { // 通过扇出索引找到所有匹配的ElementId,去重避免重复条目 var matchingElementIds = await _session .Query<Elements_ByExternalIds.Result, Elements_ByExternalIds>() .Where(x => externalIds.Contains(x.ExternalId)) .Select(x => x.ElementId) .Distinct() .ToListAsync(cancellationToken); // 加载对应的Element实体文档 var elements = await _session.LoadAsync<Element>(matchingElementIds, cancellationToken); return Result.Success(elements); } catch (Exception ex) { return Result.Failure<IEnumerable<Element>>($"Failed {ex.Message}"); } }
2. 简化方案:使用动态查询(无需自定义索引)
RavenDB支持直接对文档集合属性做交集查询,无需手动创建扇出索引,代码更简洁:
public async Task<Result<IEnumerable<Element>>> GetElementsWhichContainExternalIds(IEnumerable<string> externalIds, CancellationToken cancellationToken) { try { var elements = await _session .Query<Element>() .Where(element => element.ExternalIds.Any(id => externalIds.Contains(id))) .ToListAsync(cancellationToken); return Result.Success(elements); } catch (Exception ex) { return Result.Failure<IEnumerable<Element>>($"Failed {ex.Message}"); } }
RavenDB会自动为ExternalIds集合生成合适的动态索引,满足交集匹配需求。
内容的提问来源于stack exchange,提问作者milorad
相关产品推荐
相关产品推荐

