背景:我们使用与我们的mongo分开的ElasticSearch来搜索事物。一旦查询返回id的列表,我们需要从mongo中提取项目,并按照它们来自ES的顺序对它们进行排序。
问题:如何找到id的列表,然后将结果排序为与列表相同的顺序。它可能是这样的:
// NOTE: The following code does not work.
JobsCollection
.Find(Builders<JobModel>.Filter.In(j => j.Id, idList))
.OrderBy(j => idList.IndexOf(j.Id)) // <-- Something like this
我可能只是在得到对象之后对它进行排序,如果我无法解决它,但如果mongo驱动程序可以为我做,那将是很酷的。
没有一种好方法可以在MongoDB服务器端进行排序。即使有可能,我怀疑与客户端排序相比,您获得了一些性能提升。大部分时间用于从数据库读取数据并转移到客户端,这对于服务器和客户端排序是相同的。
你的LINQ解决方案对我来说很好。然而,它为每个列表元素使用List.IndexOf()
,为您提供O(n ^ 2)的复杂性。这个LINQ可能会在大型列表上表现不佳。
我建议改进它并创建一个字典,将id值映射到列表中的索引:
var idMap = idList.Select((x, i) => new { Value = x, Index = i })
.ToDictionary(x => x.Value, x => x.Index);
var sorted = JobsCollection
.Find(Builders<JobModel>.Filter.In(j => j.Id, idList))
.ToList()
.OrderBy(j => idMap[j.Id]);
这将给你O(n * log(n))的复杂性,这要好得多。
更新(关于不在问题中的代码):
我相信不工作代码你的意思是它无法编译。问题是Find
方法返回IFindFluent<TDocument, TDocument>
。 IFindFluent
是一个游标,你不能直接在LINQ表达式中使用它。为了使你的代码编译和工作,在.ToEnumerable()
结果上添加Find
调用:
JobsCollection
.Find(Builders<JobModel>.Filter.In(j => j.Id, idList))
.ToEnumerable()
.OrderBy(j => idList.IndexOf(j.Id));