0

I'm trying to get documents from MongoDB such way:

    public async Task<IEnumerable<UnitModel>> GetUnits(string race)
    {
        var units = collection.Aggregate().Match(x => x.Race == race && 
            (x.Attack < x.Def1 || x.Attack < x.Def2) && 
            (x.UnitType == UnitType.Warrior || x.UnitType == UnitType.Archer));
        return await units.ToListAsync();
    }

But the following error occurs:

Unsupported filter: ({document}{attack} < {document}{def1}). 

Using Where with the same predicate leads to the same result. What I'm doing wrong?

UPDATE:

As far as I understand C# driver is unable to transform this query. Now I'm trying to use pipeline. First of all I tested the query in shell and it works:

db.units.aggregate([
    {
        $addFields: {
            cDiff: {$cmp: ['$attack','$def1']},
            iDiff: {$cmp: ['$attack','$def2']}
        }
    },
    {
        $match: {
            $and: [
                {race: "elf"},
                {$or: [
                    {
                        cDiff:{$eq:-1}
                    },
                    {
                        iDiff:{$eq:-1}
                    }
                ]},
                {$or: [{
                    "unitType": "Warrior"
                },
                {
                    "unitType": "Archer"
                }]}
            ]
        }
    }
]).pretty()

Now I'm stucked with transforming it to C#:

    public async Task<IEnumerable<UnitModel>> GetDeffenceUnits(Race race)
    {
        PipelineDefinition<UnitModel, UnitModel> pipeline = new BsonDocument[]
        {
            new BsonDocument{
                { "$addFields", new BsonDocument
                    {
                        { "iDiff:", new BsonDocument { { "$cmp", new BsonArray { "$attack", "$def1" } } } },
                        { "cDiff:", new BsonDocument { { "$cmp", new BsonArray { "$attack", "$def2" } } } }
                    }
                }
            },
            new BsonDocument
            {
                {
                    "$match", new BsonDocument
                    {
                        {
                            "$and", new BsonArray
                            {
                                new BsonDocument
                                {
                                    { "race", race.GetEnumDisplayName() }
                                },
                                new BsonDocument
                                {
                                    {
                                        "$or", new BsonArray
                                        {
                                            new BsonDocument
                                            {
                                                { "iDiff", new BsonDocument { { "$eq", -1 } } }
                                            },
                                            new BsonDocument
                                            {
                                                { "cDiff", new BsonDocument { { "$eq", -1 } } }
                                            }
                                        }
                                    }
                                },
                                new BsonDocument
                                {
                                    {
                                        "$or", new BsonArray
                                        {
                                            new BsonDocument
                                            {
                                                { "unitType", UnitType.Warrior.GetEnumDisplayName() }
                                            },
                                            new BsonDocument
                                            {
                                                { "unitType", UnitType.Warrior.GetEnumDisplayName() }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        };

        var units = collection.Aggregate(pipeline);                
        return await units.ToListAsync();
    }

This query returns an empty list. What did I miss?


UPDATE 2 Adding UnitModel:

[BsonIgnoreExtraElements]
public class UnitModel
{
    public string Name { get; set; }
    // enum
    public Race Race { get; set; }
    public double Expenses { get; set; }
    public double Speed { get; set; }
    public double Capacity { get; set; }
    public double Attack { get; set; }
    public double Def1 { get; set; }
    public double Def2 { get; set; }
    // enum
    public UnitType UnitType { get; set; }
    public ResourcesModel TrainingCost { get; set; }
    public ResourcesModel ResearchCost { get; set; }
    public TimeSpan ResearchTime { get; set; }
    public TimeSpan TrainingTime { get; set; }
}

public class ResourcesModel
{
    public int Wood { get; set; }
    public int Gold { get; set; }
    public int Iron { get; set; }
}

UPDATE 3 trying to see the mongodb request:

        var units = collection.Aggregate(pipeline);
        var queryToMongo = units.ToString();
        return await units.ToListAsync(); 

UPDATE 4 Convention packs:

        var packEnum = new ConventionPack
        {
            new EnumRepresentationConvention(BsonType.String)
        };
        ConventionRegistry.Register("EnumStringConvention", packEnum, t => true);

        var packCamelCase = new ConventionPack
        {
            new CamelCaseElementNameConvention()
        };
        ConventionRegistry.Register("camel case",
                                    packCamelCase,
                                    t => t.FullName.StartsWith("TTB.DAL.Models"));
13
  • Can you add UnitModel too? Commented Nov 25, 2019 at 13:48
  • @Mahdi, updated Commented Nov 25, 2019 at 17:53
  • @NikitaFedorov you should be able to get and inspect the generated query using collection.Aggregate(pipeline).ToString() Commented Nov 25, 2019 at 18:01
  • Does every document contains Attack and Def1 properties? if not, try changing to nullable double and post your observations. Commented Nov 25, 2019 at 18:12
  • @jcruz ToString returns type name Commented Nov 25, 2019 at 19:03

1 Answer 1

1

You know, this is really embarrassing...when I copied my shell query to C#, I forgot to remove colons after iDiff and cDiff. After I removed them the query worked perfectly.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.