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"));
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.