1

*モンゴ初心者はこちら

組み合わせてクエリする必要がある数百の数値フィールドを含むドキュメントがあります。

var collection = _myDB.GetCollection<MyDocument>("collection");
IMongoQuery mongoQuery; // = Query.GT("field", value1).LT(value2);
foreach (MyObject queryObj in Queries)
{
    // I have several hundred fields such as Height, that are in queryObj
    // how do I build a "boolean" query in C# 
    mongoQuery = Query.GTE("Height", Convert.ToInt16(queryObj.Height * lowerbound));
}

高さ (例: 幅、面積、周長など) などの数百のフィールドがあり、それらは queryObj にあります。各フィールドの範囲クエリを結合する C# で「ブール値」クエリを作成するにはどうすればよいですか。

Query.GT("field", value1).LT(value2); の例を使用しようとしましたが、コンパイラは LT(Value) 構造を受け入れません。いずれにしても、各数値フィールド値をループして複雑なブール クエリを作成できる必要があります。

初心者を助けてくれてありがとう。

4

1 に答える 1

4

編集3:

わかりました、複雑なクエリを作成するためのコードが既に配置されているようです。その場合、コンパイラの問題を修正する必要がありました。あなたが次のことをしたいと仮定しています(x > 20 && x < 40) && (y > 30 && y < 50)...

var collection = _myDB.GetCollection<MyDocument>("collection");
var queries = new List<IMongoQuery>();

foreach (MyObject queryObj in Queries)
{
    //I have several hundred fields such as Height, that are in queryObj
    //how do I build a "boolean" query in C# 

    var lowerBoundQuery = Query.GTE("Height", Convert.ToInt16(queryObj.Height * lowerbound));
    var upperBoundQuery = Query.LTE("Height", Convert.ToInt16(queryObj.Height * upperbound));

    var query = Query.And(lowerBoundQuery, upperBoundQuery);
    queries.Add(query);
}

var finalQuery = Query.And(queries); 
/*
    if you want to instead do an OR,
    var finalQuery = Query.Or(queries); 
*/

元の回答。

var list = _myDb.GetCollection<MyDoc>("CollectionName")
                .AsQueryable<MyDoc>()
                .Where(x => 
                         x.Height > 20 && 
                         x.Height < 40)
                .ToList();

Query.GT("field", value1).LT(value2); の例を使用しようとしましたが、コンパイラは LT(Value) 構造を受け入れません。

公式の C# ドライバーを使用している場合は、linq を使用して MongoDB にクエリを実行できます。それは私が思うコンパイラの問題を解決するはずです。

私が考えているより興味深い質問は、その複雑なブールクエリをどのように作成するのかということです。

1 つのオプションは、動的に を構築しExpression、それをWhere

私の同僚は、似たようなものに次のコードを使用しています...

    public static IQueryable<T> Where<T>(this IQueryable<T> query,
        string column, object value, WhereOperation operation)
    {
        if (string.IsNullOrEmpty(column))
            return query;

        ParameterExpression parameter = Expression.Parameter(query.ElementType, "p");

        MemberExpression memberAccess = null;
        foreach (var property in column.Split('.'))
            memberAccess = MemberExpression.Property
               (memberAccess ?? (parameter as Expression), property);

        //change param value type
        //necessary to getting bool from string
        ConstantExpression filter = Expression.Constant
            (
                Convert.ChangeType(value, memberAccess.Type)
            );

        //switch operation
        Expression condition = null;
        LambdaExpression lambda = null;
        switch (operation)
        {
            //equal ==
            case WhereOperation.Equal:
                condition = Expression.Equal(memberAccess, filter);
                lambda = Expression.Lambda(condition, parameter);
                break;
            //not equal !=
            case WhereOperation.NotEqual:
                condition = Expression.NotEqual(memberAccess, filter);
                lambda = Expression.Lambda(condition, parameter);
                break;
            //string.Contains()
            case WhereOperation.Contains:
                condition = Expression.Call(memberAccess,
                    typeof(string).GetMethod("Contains"),
                    Expression.Constant(value));
                lambda = Expression.Lambda(condition, parameter);
                break;
        }


        MethodCallExpression result = Expression.Call(
               typeof(Queryable), "Where",
               new[] { query.ElementType },
               query.Expression,
               lambda);

        return query.Provider.CreateQuery<T>(result);
    }

public enum WhereOperation
{
    Equal,
    NotEqual,
    Contains
}

現在==&&のみをサポートしていますが、実装はそれほど難しくない!=はずです。>=<=

Expression クラスからいくつかのヒントを得ることができます: http://msdn.microsoft.com/en-us/library/system.linq.expressions.expression.aspx

編集:

var props = ["Height", "Weight", "Age"];
var query = _myDb.GetCollection<MyDoc>("CName").AsQueryable<MyDoc>();
foreach (var prop in props) 
{
   query = query.Where(prop, GetLowerLimit(queryObj, prop), WhereOperation.Between, GetUpperLimit(queryObj, prop));  
}
// the above query when iterated over, will result in a where clause that joins each individual `prop\condition` with an `AND`. 
// The code above will not compile. The `Where` function I wrote doesnt accept 4 parameters. You will need to implement the logic for that yourself. Though it ought to be straight forward I think... 

編集2:

linq を使用したくない場合でも、Mongo Query を使用できます。Query.And()とを使用してクエリを作成するだけですQuery.Or()

        // I think this might be deprecated. Please refer the release notes for the C# driver version 1.5.0  
        Query.And(Query.GTE("Salary", new BsonDouble(20)), Query.LTE("Salary", new BsonDouble(40)), Query.GTE("Height", new BsonDouble(20)), Query.LTE("Height", new BsonDouble(40)))

        // strongly typed version
        new QueryBuilder<Employee>().And(Query<Employee>.GTE(x => x.Salary, 40), Query<Employee>.LTE(x => x.Salary, 60), Query<Employee>.GTE(x => x.HourlyRateToClients, 40), Query<Employee>.LTE(x => x.HourlyRateToClients, 60))
于 2012-07-26T11:45:55.493 に答える