如何忽略我认为基于属性重复的额外结果?

Posted

技术标签:

【中文标题】如何忽略我认为基于属性重复的额外结果?【英文标题】:How to ignore extra results that I consider duplicates based on property? 【发布时间】:2020-06-08 23:06:45 【问题描述】:

这可能是一个很长的镜头,但我们开始吧。假设我有以下文档定义:

公共类Test1 公共 ObjectId Id get;set; 公共 int NonUniqueId 获取;放; 公共字符串名称 获取;放; 公共小数价格 得到;放;

使用IMongoCollection<Test1>,我可以过滤结果以记录Name = "somevalue",按Price排序并仅返回10行。

var builder = Builders.Filters; var filter = builder.Where(x=>x.Name == "somevalue"); var result = await collection.Find(filter).SortBy(x=>x.Price).Limit(10).ToListAsync();

现在到手头的问题。如果过滤器返回了多个文档(带有Name = "somevalue")并且NonUniqueId 在该集合中多次出现,我想排除重复的NonUniqueId 并仅返回具有最低Price 的文档。

这个逻辑在代码中很容易实现:获取 10 个结果,如果其中任何一个是“重复的”(即 NonUniqueId 出现多次),保留价格最低的一个并运行另一个搜索,不包括这个NonUniqueId。但是,它需要多个数据库调用,这不是很好(最坏的情况下最多 10 个)。

在 MongoDB(使用 C# 驱动程序)中,有没有办法根据属性忽略这些“重复”结果,理想情况下,只返回另一个属性的最小值(或任何具有相同效果的东西)?

【问题讨论】:

【参考方案1】:

试试这个管道:

db.Product.aggregate([
    
      $match:  Name: "book" 
    ,
    
      $sort:  Price: 1 
    ,
    
      $group: 
        _id: "$NonUniqueId",
        product:  $first: "$$ROOT" 
      
    ,
    
      $replaceWith: "$product"
    
])

https://mongoplayground.net/p/sqSjiXQhdlF

更新:添加了c#

由于需要投影,c#版本有点不方便:

var result = collection.AsQueryable()
               .Where(p => p.Name == "book")
               .OrderBy(p => p.Price)
               .GroupBy(p => p.NonUniqueId)
               .Select(g => new Product
               
                   Id = g.First().Id,
                   Name = g.First().Name,
                   NonUniqueId = g.First().NonUniqueId,
                   Price = g.First().Price
               )
               .ToList();

测试程序:

using MongoDB.Driver;
using MongoDB.Driver.Linq;
using MongoDB.Entities;
using MongoDB.Entities.Core;
using System.Linq;

namespace ***

    public class Product : Entity
    
        public int NonUniqueId  get; set; 
        public string Name  get; set; 
        public decimal Price  get; set; 
    

    public static class Program
    
        private static void Main()
        
            new DB("test");

            var result = DB.Queryable<Product>()
                           .Where(p => p.Name == "book")
                           .OrderBy(p => p.Price)
                           .GroupBy(p => p.NonUniqueId)
                           .Select(g => new Product
                           
                               ID = g.First().ID,
                               Name = g.First().Name,
                               NonUniqueId = g.First().NonUniqueId,
                               Price = g.First().Price
                           )
                           .ToList();
        
    

【讨论】:

是的...投影将是这里的问题。该集合已获得 100000 份文档。我并不特别喜欢下载所有这些,但您可以从驱动程序运行原始查询。极限射门会绕组吗? @Dawid 您可以毫无问题地进行限制。限制是施加在光标 afaik 上的。 @DawidO 认为您可能对使用 c# 运行原始查询的更好方法感兴趣。看看我写的this library。 也许我在这里遗漏了一些明显的东西,我不能这样做 collection.AsQueryable() 因为我不想在我的本地机器上下载整个集合。关于库,您能否提供更多详细信息如何将其与我提供的代码示例集成? @DawidO 给你:gist.github.com/dj-nitehawk/bda542ca93609fe12a670ccab89dc1d2【参考方案2】:

尝试Distinct方法,如this答案所示。您甚至可以定义一个自定义的Equals 函数(通过定义一个实现IEqualityComparer 的类)来执行您需要执行的检查

【讨论】:

我不需要比较 C# 对象。我希望 Mongo 为我完成繁重的工作。

以上是关于如何忽略我认为基于属性重复的额外结果?的主要内容,如果未能解决你的问题,请参考以下文章

基于使用jQuery的属性的条件jQuery选择器[重复]

向基于类的视图添加额外内容并对其进行过滤

基于对象属性对数组进行排序 - Javascript [重复]

如何使用 FsCheck 生成随机数作为基于属性的测试的输入

基于 MySQL 的数据库实践(更名运算)

使用基于 GraphQL 游标的分页避免代码重复