/// <summary> /// Gets the aggregate value, by grouping, of the values in the given entity field. /// </summary> /// <returns>The sum of the values of the given property name for the entities in the <see cref="DataStore{T}"/>.</returns> /// <param name="groupField">Property name of field to be used in grouping.</param> /// <param name="aggregateField">Property name of field to be used in aggregation. This is not necessary when using the <see cref="KinveyXamarin.EnumReduceFunction.REDUCE_FUNCTION_COUNT"/> method.</param> /// <param name="query">[optional] Query used to filter results prior to aggregation.</param> /// <param name="cacheDelegate">Delegate used to return the sum aggregate value based on what is available in offline cache.</param> /// <param name="ct">[optional] CancellationToken used to cancel the request.</param> public async Task <List <GroupAggregationResults> > GroupAndAggregateAsync(EnumReduceFunction reduceFunction, string groupField = "", string aggregateField = "", IQueryable <object> query = null, KinveyDelegate <List <GroupAggregationResults> > cacheDelegate = null, CancellationToken ct = default(CancellationToken)) { FindAggregateRequest <T> findByAggregateQueryRequest = new FindAggregateRequest <T>(client, collectionName, reduceFunction, cache, storeType.ReadPolicy, DeltaSetFetchingEnabled, cacheDelegate, query, groupField, aggregateField); ct.ThrowIfCancellationRequested(); return(await findByAggregateQueryRequest.ExecuteAsync()); }
/// <summary> /// Initializes a new instance of the <see cref="T:KinveyXamarin.FindAggregateRequest`1"/> class. /// </summary> /// <param name="client">Client.</param> /// <param name="collection">Collection.</param> /// <param name="reduceFunction">Reduce function.</param> /// <param name="cache">Cache.</param> /// <param name="policy"> The <see cref="ReadPolicy"/> to be used for this request.</param> /// <param name="deltaSetFetchingEnabled">If set to <c>true</c> delta set fetching enabled.</param> /// <param name="cacheDelegate">Cache delegate.</param> /// <param name="query">[optional] Query used to filter the results that are to be aggregated.</param> /// <param name="groupField">Property name to be used for grouping.</param> /// <param name="aggregateField">Property name to be used for aggregation.</param> public FindAggregateRequest(AbstractClient client, string collection, EnumReduceFunction reduceFunction, ICache <T> cache, ReadPolicy policy, bool deltaSetFetchingEnabled, KinveyDelegate <List <GroupAggregationResults> > cacheDelegate, IQueryable <object> query, string groupField, string aggregateField) : base(client, collection, cache, query, policy, deltaSetFetchingEnabled) { this.cacheDelegate = cacheDelegate; this.reduceFunction = reduceFunction; this.groupField = groupField; this.aggregateField = aggregateField; }
public NetworkRequest <T> BuildGetAggregateRequest <T>(string collectionName, EnumReduceFunction reduceFunction, string query, string groupField, string aggregateField) { string REST_PATH = "appdata/{appKey}/{collectionName}/_group"; var urlParameters = new Dictionary <string, string>(); urlParameters.Add("appKey", ((KinveyClientRequestInitializer)client.RequestInitializer).AppKey); urlParameters.Add("collectionName", collectionName); JObject keyval = new JObject(); if (!String.IsNullOrEmpty(groupField)) { keyval.Add(groupField, true); } JObject initialval = new JObject(); JObject httpBodyContent = new JObject(); httpBodyContent.Add("key", keyval); string reduce = String.Empty; switch (reduceFunction) { case EnumReduceFunction.REDUCE_FUNCTION_SUM: initialval.Add("result", 0); reduce = $"function(doc,out){{ out.result += doc.{aggregateField}; }}"; break; case EnumReduceFunction.REDUCE_FUNCTION_MIN: initialval.Add("result", Int32.MaxValue); reduce = $"function(doc,out){{ out.result = Math.min(out.result, doc.{aggregateField}); }}"; break; case EnumReduceFunction.REDUCE_FUNCTION_MAX: initialval.Add("result", Int32.MinValue); reduce = $"function(doc,out){{ out.result = Math.max(out.result, doc.{aggregateField}); }}"; break; case EnumReduceFunction.REDUCE_FUNCTION_AVERAGE: initialval.Add("result", 0); initialval.Add("count", 0); reduce = $"function(doc,out){{ out.result = (((out.result * out.count) + doc.{aggregateField}) / (out.count += 1)); }}"; break; default: // TODO throw new KinveyException() break; } httpBodyContent.Add("initial", initialval); httpBodyContent.Add("reduce", reduce); if (!String.IsNullOrEmpty(query)) { const char CHAR_CURLY_BRACE_OPENING = '{'; const char CHAR_CURLY_BRACE_CLOSING = '}'; const char CHAR_COLON = ':'; const char CHAR_DOUBLE_QUOTATION_MARK = '"'; JObject condition = new JObject(); query = query.TrimStart(CHAR_CURLY_BRACE_OPENING).TrimEnd(CHAR_CURLY_BRACE_CLOSING); string[] cond = query.Split(CHAR_COLON); cond[0] = cond[0].TrimStart(CHAR_DOUBLE_QUOTATION_MARK).TrimEnd(CHAR_DOUBLE_QUOTATION_MARK); cond[1] = cond[1].TrimStart(CHAR_DOUBLE_QUOTATION_MARK).TrimEnd(CHAR_DOUBLE_QUOTATION_MARK); condition.Add(cond[0], cond[1]); httpBodyContent.Add("condition", condition); } NetworkRequest <T> findAggregateQuery = new NetworkRequest <T>(client, "POST", REST_PATH, httpBodyContent, urlParameters); client.InitializeRequest(findAggregateQuery); return(findAggregateQuery); }
public List <GroupAggregationResults> GetAggregateResult(EnumReduceFunction reduceFunction, string groupField, string aggregateField, Expression query) { List <GroupAggregationResults> localAggregateResults = new List <GroupAggregationResults>(); List <object> listValues = new List <object>(); PropertyInfo propInfo = typeof(T).GetRuntimeProperty(aggregateField); if (propInfo != null && IsTypeNumber(propInfo.PropertyType)) { int skipNumber = 0; int takeNumber = 0; bool sort = false; LambdaExpression exprSort = null; var lambdaExpr = ConvertQueryExpressionToFunction(query, ref skipNumber, ref takeNumber, ref sort, ref exprSort); if (String.IsNullOrEmpty(groupField)) { // Not grouping results be a specified field, so just aggregate over all entities // that pass through the query filter, if provided. GroupAggregationResults gar = new GroupAggregationResults(); gar.GroupField = null; // TODO do "skip" and "take" have to be taken into account in group aggregate functions? if (lambdaExpr != null) { listValues = (from t in dbConnectionSync.Table <T>().Where(lambdaExpr) select t.GetType().GetRuntimeProperty(aggregateField).GetValue(t, null)).ToList(); } else { listValues = (from t in dbConnectionSync.Table <T>() select t.GetType().GetRuntimeProperty(aggregateField).GetValue(t, null)).ToList(); } switch (reduceFunction) { case EnumReduceFunction.REDUCE_FUNCTION_SUM: foreach (int val in listValues) { gar.Result += val; } break; case EnumReduceFunction.REDUCE_FUNCTION_MIN: gar.Result = int.MaxValue; foreach (int val in listValues) { gar.Result = Math.Min(gar.Result, val); } break; case EnumReduceFunction.REDUCE_FUNCTION_MAX: gar.Result = int.MinValue; foreach (int val in listValues) { gar.Result = Math.Max(gar.Result, val); } break; case EnumReduceFunction.REDUCE_FUNCTION_AVERAGE: int count = 0; int total = 0; foreach (int val in listValues) { total += val; count++; } gar.Result = total / count; break; default: // TODO throw new KinveyException break; } localAggregateResults.Add(gar); } else { // A grouping field was supplied, so aggregate // result per group created on the group field IEnumerable <IGrouping <object, T> > grouplist; if (lambdaExpr != null) { grouplist = from t in dbConnectionSync.Table <T>().Where(lambdaExpr) group t by t.GetType().GetRuntimeProperty(groupField).GetValue(t, null); } else { grouplist = from t in dbConnectionSync.Table <T>() group t by t.GetType().GetRuntimeProperty(groupField).GetValue(t, null); } foreach (var grouping in grouplist) { int result = 0; listValues = (from x in grouping select x.GetType().GetRuntimeProperty(aggregateField).GetValue(x, null)).ToList(); GroupAggregationResults gar = new GroupAggregationResults(); gar.GroupField = grouping.Key.ToString(); switch (reduceFunction) { case EnumReduceFunction.REDUCE_FUNCTION_SUM: foreach (int val in listValues) { result += val; } break; case EnumReduceFunction.REDUCE_FUNCTION_MIN: result = int.MaxValue; foreach (int val in listValues) { result = Math.Min(result, val); } break; case EnumReduceFunction.REDUCE_FUNCTION_MAX: result = int.MinValue; foreach (int val in listValues) { result = Math.Max(result, val); } break; case EnumReduceFunction.REDUCE_FUNCTION_AVERAGE: int count = 0; int total = 0; foreach (int val in listValues) { total += val; count++; } result = total / count; break; default: // TODO throw new KinveyException break; } gar.Result = result; localAggregateResults.Add(gar); } } } return(localAggregateResults); }