How should I structure my nested reactivemongo calls in my play2 application?

这一生的挚爱 提交于 2019-12-04 22:13:24

I am not an expert in mongoDB neither in ReactiveMongo but it seems that you are trying to use a NoSQL database in the same way as you would use standard SQL databases. Note that mongoDB is asynchronous which means that operations may be executed in some future, this is why insertion/update operations do not return affected documents. Regarding your questions:

1 To insert the objects if they do not exist and get the information of which objects that have been inserted?

You should probably look at the mongoDB db.collection.update() method and call it with the upsert parameter as true. If you can afford it, this will either update documents if they already exist in database or insert them otherwise. Again, this operation does not return affected documents but you can check how many documents have been affected by accessing the last error. See reactivemongo.api.collections.GenericCollection#update which returns a Future[LastError].

2 For all the objects that are inserted, add them to a list and then return it with the Ok() call.

Once again, inserted/updated documents will not be returned. If you really need to return the complete affected document back, you will need to make another query to retrieve matching documents.

I would probably rewrite your code this way (without error/failure handling):

def dostuff() = Action {
    implicit request =>
        form.bindFromRequest.fold(
            errors => BadRequest(views.html.invite(errors)),
            form => {
                val objectsReadyForSave = createObjects(form.companyId, form.companyName, sms_pattern.findAllIn(form.phoneNumbers).toSet)
                Async {
                    val operations = for {
                        data <- objectsReadyForSave
                    } yield collection.update(BSONDocument("cId" -> data.cId.get, "userId" -> data.userId.get), data, upsert = true)

                    Future.sequence(operations).map {
                        lastErrors =>
                            Ok("Documents probably inserted/updated!")
                    }
                }
            }
        )
}

See also Scala Futures: http://docs.scala-lang.org/overviews/core/futures.html

This is really useful! ;)

Here's how I'd rewrote it.

def dostuff() = Action { implicit request =>
  form.bindFromRequest.fold(
    errors => BadRequest(views.html.invite(errors)),
    form   => {
      createObjects(form.companyId,
        form.companyName,
        sms_pattern.findAllIn(form.phoneNumbers).toSet).map(ƒ)

      Ok(views.html.invite(form))
    }
  )
}

// ...
// In the model
// ...

def ƒ(cId: Option[String], userId: Option[String], logger: Logger) = {
  // You need to handle the case where obj.cId or obj.userId are None
  collection.find(BSONDocument("cId" -> obj.cId.get, "userId" -> obj.userId.get))
    .cursor
    .headOption
    .map { maybeFound =>
      maybeFound map { _ =>
        logger.info("Record found, do not insert")
      } getOrElse {
        collection.insert(obj)
      }
    }
}

There may be some syntax errors, but the idea is there.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!