【问题标题】:Match "x out of y" fields in a document匹配文档中的“x out of y”字段
【发布时间】:2020-05-03 14:19:09
【问题描述】:

我正在编写一个服务来处理游戏的禁令,我目前在尝试编写 MongoDB 查询时有点卡住了。目前我有一个“用户”对象的集合,这些对象看起来像这样:

public class User
{
    public List<Ban> Bans { get; set; }

    // some irrelevant additional fields
}

public class Ban
{
    public HardwareId HWID { get; set; }

    public DateTime Expires { get; set; }

    // some irrelevant additional fields
}

public class HardwareId : IEquatable<HardwareId>
{
    public string Field1 { get; set; }

    public string Field2 { get; set; }

    public string Field3 { get; set; }

    public string Field4 { get; set; }

    public bool Equals([AllowNull] HardwareId other)
    {
        if (ReferenceEquals(other, null)) return false;
        if (ReferenceEquals(this, other)) return true;

        return Field1 == other.Field1 &&
            Field2 == other.Field2 &&
            Field3 == other.Field3 &&
            Field4 == other.Field4;
    }
}

我想要做的是有一个查询来查找所有被禁止的用户,其中 HWID 说 4 个字段中的 3 个匹配。目前我有一个查询,只能找到 HWID 完全匹配的用户(由于 Equals() 实现),但我想更改它。我当前的代码如下所示:

public Ban FindBan(HardwareId hwid)
{
    var banBuilder = Builders<Ban>.Filter;
    var hwidFilter = banBuilder.Eq(b => b.HWID, hwid);
    var expFilter = banBuilder.Gt(b => b.Expires, DateTime.UtcNow);
    var banFilter = banBuilder.And(hwidFilter, expFilter);

    var user = _users.Find(Builders<User>.Filter.ElemMatch(p => p.Bans, banFilter)).FirstOrDefault();
    if (user != null)
    {
        return user.Bans[0];
    }

    return null;
}

我能想到的唯一解决方法是在 Equals() 函数中编写“意大利面条式 if 语句”,但我想要一个动态解决方案,以后可以在 HardwareId 类中添加多个“字段”下线。 FindBan() 函数目前的另一个问题是它返回“user.Bans[0]”而不是找到的实际禁令,但我想我可以通过按到期排序来解决这个问题。

【问题讨论】:

    标签: c# mongodb .net-core


    【解决方案1】:

    这是一种至少匹配 3 个 HWID 字段的方法:

    var numFieldsToMatch = 3;
    
    var hwid = {
        Field1: "one",
        Field2: "two",
        Field3: "three",
        Field4: "four"
    };
    
    db.User.find({
        $expr: {
            $anyElementTrue: {
                $map: {
                    input: "$Bans",
                    in: {
                        $gte: [{
                            $size: {
                                $filter: {
                                    input: { $objectToArray: "$$this.HWID" },
                                    cond: {
                                        $or: [
                                            { $and: [{ $eq: ["$$this.k", "Field1"] }, { $eq: ["$$this.v", hwid.Field1] }] },
                                            { $and: [{ $eq: ["$$this.k", "Field2"] }, { $eq: ["$$this.v", hwid.Field2] }] },
                                            { $and: [{ $eq: ["$$this.k", "Field3"] }, { $eq: ["$$this.v", hwid.Field3] }] },
                                            { $and: [{ $eq: ["$$this.k", "Field4"] }, { $eq: ["$$this.v", hwid.Field4] }] }
                                        ]
                                    }
                                }
                            }
                        }, numFieldsToMatch]
                    }
                }
            }
        }
    })
    

    https://mongoplayground.net/p/MPwB14o6kuO

    无法将此 mongo 查询转换为 c# 驱动程序代码 afaik。 请参阅 here 了解使用 c# 运行此程序的简单方法。

    【讨论】:

      【解决方案2】:

      您可以编写类似于 Equals 的方法(或对其进行更改),以便将每个条件匹配到一个数组中

      
      
          FldArr[0] = (Field1 == other.Field1);
          FldArr[1] = (Field2 == other.Field2);
          FldArr[2] = (Field3 == other.Field3);
          FldArr[3] = (Field4 == other.Field4);
      
      

      然后通过使用 LINQ for FldArr,您可以找到 3/4 为真条件。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-10-04
        • 2019-08-20
        • 1970-01-01
        • 2022-07-13
        • 1970-01-01
        • 1970-01-01
        • 2013-08-20
        相关资源
        最近更新 更多