migrating aggregation to 11.13

62 views
Skip to first unread message

Alexandre Russel

unread,
Jun 23, 2016, 12:43:24 AM6/23/16
to ReactiveMongo - http://reactivemongo.org
Hi,

 I am trying to migrate to 0.11.13, hopefully without using any deprecated code, I'm having a hard time using both the new database that return a Future of a collection with the import of the aggregate framework. The first thing been that now, I have to do my import inside each function as I need to map the database to get hold of a collection. The other issue is that the code just doesn't compile. I've updated a previous example to show the issues (https://github.com/arussel/reactivemongo-lock/tree/local-mongo-2_6_10). The code that is not compiling is:

  def myaggregate() = collection.flatMap {
    coll =>
      import coll.BatchCommands.AggregationFramework._
      coll.aggregate(Group(JsString("$state"))("totalPop" -> SumField("population")),
        List(Match(Json.obj("totalPop" -> Json.obj("$gte" -> 10000000L)))))
  }

it gives the error:

[error] /home/arussel/MotionMath/git/reactivemongo-lock/app/models/A.scala:22: no type parameters for method flatMap: (f: reactivemongo.play.json.collection.JSONCollection => scala.concurrent.Future[S])(implicit executor: scala.concurrent.ExecutionContext)scala.concurrent.Future[S] exist so that it can be applied to arguments (reactivemongo.play.json.collection.JSONCollection => scala.concurrent.Future[coll.BatchCommands.AggregationFramework.AggregationResult] forSome { val coll: reactivemongo.play.json.collection.JSONCollection })
[error]  --- because ---
[error] argument expression's type is not compatible with formal parameter type;
[error]  found   : reactivemongo.play.json.collection.JSONCollection => scala.concurrent.Future[coll.BatchCommands.AggregationFramework.AggregationResult] forSome { val coll: reactivemongo.play.json.collection.JSONCollection }
[error]  required: reactivemongo.play.json.collection.JSONCollection => scala.concurrent.Future[?S]
[error]   def myaggregate() = collection.flatMap {
[error]                                  ^
[error] /home/arussel/MotionMath/git/reactivemongo-lock/app/models/A.scala:23: type mismatch;
[error]  found   : reactivemongo.play.json.collection.JSONCollection => scala.concurrent.Future[coll.BatchCommands.AggregationFramework.AggregationResult] forSome { val coll: reactivemongo.play.json.collection.JSONCollection }
[error]  required: reactivemongo.play.json.collection.JSONCollection => scala.concurrent.Future[S]
[error]     coll =>
[error]          ^
[error] two errors found
[error] (compile:compileIncremental) Compilation failed


For what I understand, it complains because it doesn't know the result type of the aggregate which is only known inside the flatMap. What would be the normal way to do it ? Is there a non deprecated way to import the types without having to wait to be inside the Future ?


Thanks,
Alex

Cédric Chantepie

unread,
Jun 23, 2016, 3:19:07 AM6/23/16
to ReactiveMongo - http://reactivemongo.org
I would suggest you add the expected return type to your def, that's generally a good practice when coding an API, and there is will help the compiler (and the list readers) to understand what you want.

Alexandre Russel

unread,
Jun 23, 2016, 4:28:34 AM6/23/16
to ReactiveMongo - http://reactivemongo.org
I would but I have the same complain as the compiler, I don't know what is the return type of myaggregate as the type is Future[coll.BatchCommands.AggregationFramework.AggregationResult] and coll is only known inside the first map.

Cédric Chantepie

unread,
Jun 23, 2016, 7:06:21 AM6/23/16
to ReactiveMongo - http://reactivemongo.org
You should not have coll.BatchCommands.AggregationFramework.AggregationResult in the return type, but the type parsed from that.

You could have a look at the doc samples: http://reactivemongo.org/releases/0.11/documentation/advanced-topics/aggregation.html

Alexandre Russel

unread,
Jun 23, 2016, 7:14:25 AM6/23/16
to reacti...@googlegroups.com
I'm seeing this: 
def aggregate(col: BSONCollection): Future[col.BatchCommands.AggregationFramework.AggregationResult] = ???
which is my problem as from now on we're working with Future of collection and not collection anymore. I could add .map(_.xxx) but I would have to write a function per return type. I also can't have separate function that create the pipeline as everything as to be found inside the map of the collection. 

On Thu, Jun 23, 2016 at 1:06 PM, Cédric Chantepie <chantep...@gmail.com> wrote:
You should not have coll.BatchCommands.AggregationFramework.AggregationResult in the return type, but the type parsed from that.

You could have a look at the doc samples: http://reactivemongo.org/releases/0.11/documentation/advanced-topics/aggregation.html

--
You received this message because you are subscribed to a topic in the Google Groups "ReactiveMongo - http://reactivemongo.org" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/reactivemongo/9Ypw5daJe3Q/unsubscribe.
To unsubscribe from this group and all its topics, send an email to reactivemong...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Cédric Chantepie

unread,
Jun 23, 2016, 7:44:53 AM6/23/16
to ReactiveMongo - http://reactivemongo.org
Having AggregationResult in return types of your API, is meaningless. It's an intermediate result, tied to the MongoDB operation.

Either you return data parsed from there, or Unit (map the Future to {}).

Alexandre Russel

unread,
Jun 23, 2016, 7:55:59 AM6/23/16
to reacti...@googlegroups.com
I agree with you that this would be meaningless in the API but those function are private helper function, exactly the same than in your example. So now I have to write a function per return type instead of just the aggregate and then some mapper. I'm having the same issue with pipelines, where I have plenty helper functions that define pipeline for the aggregate, but because now the type is not known anymore, I have to copy those helper in every function that uses them. 

On Thu, Jun 23, 2016 at 1:44 PM, Cédric Chantepie <chantep...@gmail.com> wrote:
Having AggregationResult in return types of your API, is meaningless. It's an intermediate result, tied to the MongoDB operation.

Either you return data parsed from there, or Unit (map the Future to {}).

Cédric Chantepie

unread,
Jun 23, 2016, 9:13:32 AM6/23/16
to ReactiveMongo - http://reactivemongo.org
For me your internal function should not deals with the DB or Collection resolution (steps where you got Future[DefaultDB] or Future[XCollection]), first because it will make you have hard time with internal dependency types, and also because it means you let these functions have some context responsability (resolving a resource from the context), instead of being given the context resource.

def internal(coll: JSONCollection): Future[coll.BatchCommands.AggregationFramework.AggregationResults] = ???

// used where the collection is resolved properly
database
.flatMap { db => internal(db.collection[JSONCollection]("foo")) }



Also be sure the functions are required/useful, I'm really not sure there is much benefit if they mainly call the .aggregation operation (I would directly call it from the different specific cases).

Cédric Chantepie

unread,
Jun 23, 2016, 9:48:00 AM6/23/16
to ReactiveMongo - http://reactivemongo.org
Reply all
Reply to author
Forward
0 new messages