2012-07-26 69 views
1

*蒙戈新手在这里MongoDB的 - 结合多个数字范围查询(C#驱动程序)

我有一个包含几百个数字领域,我需要在组合查询的文档。

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

编辑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( “场”,值1).LT(值2);, 但是编译器不接受LT(值)构建体。

如果您使用官方的C#驱动程序,您可以使用linq查询MongoDB。这应该解决我认为的编译器问题。

我想到的更有趣的问题是,你将如何构造复杂的布尔查询?

一种选择是动态建立一个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 
} 

目前,它仅支持== & & !=,但它应该不是那么难实施>=<= ...

你可以从表达式类得到一些提示: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.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)) 
+0

嗨,感谢您的回复,但我如何建立一个范围列表例如Where(x => x.Height> 20 && x.Height < 40), y => y.Height> 30 && y.Height <60)等等。 – Mikos 2012-07-26 11:51:01

+0

最好是否有非LINQ方式?或者是LINQ我唯一的选择? – Mikos 2012-07-26 11:53:21

+0

编辑是否有帮助? .. Cuz,老实说,我不明白你在评论中写的“Where”的例子。它不会编译。 'Where'不接受'x'和'y'两个参数... – 2012-07-26 12:07:01