2

I have an application, written with Play and ReactiveMongo, where I want to:

  • Have an action that inserts a landingPage document into MongoDB.
  • Insert the new landingPage and wait for that to insert.
  • Count the new total number of landingPage documents and return that to the user.

I have this working code:

// Insert the landing page and wait for it to be inserted, so we can then get the new count of landing pages.
val futures = for {
  wr <- landingPagesCollection.insert(landingPage)
  count <- landingPagesCollection.count()
} yield count

futures.map { (count: Int) =>
  Created(Json.obj(
    "created" -> true,
    "landingPage" -> landingPage.toJson,
    "count" -> count
  ))
}

This code works fine. However, out of curiosity I want to know how to access the wr (WriteResult) value. When I changed the code to:

val futures = for {
  wr <- landingPagesCollection.insert(landingPage)
  count <- landingPagesCollection.count()
} yield (wr, count)

futures.map { (wr: WriteResult, count: Int) =>
  Created(Json.obj(
    "created" -> true,
    "message" -> s"You created landing page ${landingPage.name} (${landingPage.jobNumber}). The Git URI is '${landingPage.gitUri}'.",
    "landingPage" -> landingPage.toJson,
    "count" -> count,
    "writeResult" -> wr
  ))
}

I get the following error messages:

The error message

Can anyone please explain how to access wr in the map function?

Amy B
  • 17,874
  • 12
  • 64
  • 83

2 Answers2

8

Try to change

futures.map { (wr: WriteResult, count: Int) =>

to:

futures.map { case (wr: WriteResult, count: Int) =>

or just:

futures.map { case (wr, count) =>

Hope this helps

Nyavro
  • 8,806
  • 2
  • 26
  • 33
  • Adding `case` made it work! Thanks! Can you explain why this case makes it work? I thought case was for use in `match` blocks. – Amy B Nov 22 '15 at 13:27
  • 2
    @AmyB "An anonymous function can be defined by a sequence of cases" §8.5 http://www.scala-lang.org/files/archive/spec/2.11/08-pattern-matching.html – sumnulu Nov 23 '15 at 10:30
6

Syntax you used works if function takes 2 arguments, not a tuple

list.map((a: Int, b: String) => ...)

if you need a tuple you can do this:

list.map(tuple: (Int, String) => {
   val (num, str) = tuple
   ...
})

or pass a partial function as suggested in accepted answer. It will match against argument (it matches a tuple) and allow you to use extracted values later

list.map { case (a: Int, b: String) => ... }

note that in this case curly braces are required.

Type annotations can be dropped as they can be inferred by the compiler.

Łukasz
  • 8,555
  • 2
  • 28
  • 51